diff --git a/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java b/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java index 5f1190d67de0..9c95ebde3740 100644 --- a/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java +++ b/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java @@ -1,76 +1,61 @@ package com.thealgorithms.maths; -import java.util.Scanner; - -/* - * Find the 2 elements which are non repeating in an array +/** + * Find the 2 elements which are non-repeating in an array * Reason to use bitwise operator: It makes our program faster as we are operating on bits and not * on actual numbers. + * + * Explanation of the code: + * Let us assume we have an array [1, 2, 1, 2, 3, 4] + * Property of XOR: num ^ num = 0. + * If we XOR all the elements of the array, we will be left with 3 ^ 4 as 1 ^ 1 + * and 2 ^ 2 would give 0. Our task is to find num1 and num2 from the result of 3 ^ 4 = 7. + * We need to find the two's complement of 7 and find the rightmost set bit, i.e., (num & (-num)). + * Two's complement of 7 is 001, and hence res = 1. There can be 2 options when we Bitwise AND this res + * with all the elements in our array: + * 1. The result will be a non-zero number. + * 2. The result will be 0. + * In the first case, we will XOR our element with the first number (which is initially 0). + * In the second case, we will XOR our element with the second number (which is initially 0). + * This is how we will get non-repeating elements with the help of bitwise operators. */ public final class NonRepeatingElement { private NonRepeatingElement() { } - public static void main(String[] args) { - try (Scanner sc = new Scanner(System.in)) { - int i; - int res = 0; - System.out.println("Enter the number of elements in the array"); - int n = sc.nextInt(); - if ((n & 1) == 1) { - // Not allowing odd number of elements as we are expecting 2 non repeating - // numbers - System.out.println("Array should contain even number of elements"); - return; - } - int[] arr = new int[n]; + /** + * Finds the two non-repeating elements in the array. + * + * @param arr The input array containing exactly two non-repeating elements and all other elements repeating. + * @return An array containing the two non-repeating elements. + * @throws IllegalArgumentException if the input array length is odd. + */ + public static int[] findNonRepeatingElements(int[] arr) { + if (arr.length % 2 != 0) { + throw new IllegalArgumentException("Array should contain an even number of elements"); + } - System.out.println("Enter " + n + " elements in the array. NOTE: Only 2 elements should not repeat"); - for (i = 0; i < n; i++) { - arr[i] = sc.nextInt(); - } + int xorResult = 0; - // Find XOR of the 2 non repeating elements - for (i = 0; i < n; i++) { - res ^= arr[i]; - } - - // Finding the rightmost set bit - res = res & (-res); - int num1 = 0; - int num2 = 0; + // Find XOR of all elements + for (int num : arr) { + xorResult ^= num; + } - for (i = 0; i < n; i++) { - if ((res & arr[i]) > 0) { // Case 1 explained below - num1 ^= arr[i]; - } else { - num2 ^= arr[i]; // Case 2 explained below - } + // Find the rightmost set bit + int rightmostSetBit = xorResult & (-xorResult); + int num1 = 0; + int num2 = 0; + + // Divide the elements into two groups and XOR them + for (int num : arr) { + if ((num & rightmostSetBit) != 0) { + num1 ^= num; + } else { + num2 ^= num; } - - System.out.println("The two non repeating elements are " + num1 + " and " + num2); } + + return new int[] {num1, num2}; } - /* - * Explanation of the code: - * let us assume we have an array [1,2,1,2,3,4] - * Property of XOR: num ^ num = 0. - * If we XOR all the elemnets of the array we will be left with 3 ^ 4 as 1 ^ 1 - * and 2 ^ 2 would give - * 0. Our task is to find num1 and num2 from the result of 3 ^ 4 = 7. We need to - * find two's - * complement of 7 and find the rightmost set bit. i.e. (num & (-num)) Two's - * complement of 7 is 001 - * and hence res = 1. There can be 2 options when we Bitise AND this res with - * all the elements in our - * array - * 1. Result will come non zero number - * 2. Result will be 0. - * In the first case we will XOR our element with the first number (which is - * initially 0) - * In the second case we will XOR our element with the second number(which is - * initially 0) - * This is how we will get non repeating elements with the help of bitwise - * operators. - */ } diff --git a/src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java b/src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java new file mode 100644 index 000000000000..5f35cfe68a7a --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java @@ -0,0 +1,30 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class NonRepeatingElementTest { + + private record TestData(int[] input, int[] expected) { + } + + private static Stream provideTestCases() { + return Stream.of(new TestData(new int[] {1, 2, 1, 3, 2, 4}, new int[] {3, 4}), new TestData(new int[] {-1, -2, -1, -3, -2, -4}, new int[] {-3, -4}), new TestData(new int[] {-1, 2, 2, -3, -1, 4}, new int[] {-3, 4})); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void testFindNonRepeatingElements(TestData testData) { + int[] result = NonRepeatingElement.findNonRepeatingElements(testData.input); + assertArrayEquals(testData.expected, result); + } + + @Test + public void testFindNonRepeatingElementsWithLargeNumbers() { + assertArrayEquals(new int[] {200000, 400000}, NonRepeatingElement.findNonRepeatingElements(new int[] {100000, 200000, 100000, 300000, 400000, 300000})); + } +}