-
Notifications
You must be signed in to change notification settings - Fork 19.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor:
NonRepeatingElement
(#5375)
- Loading branch information
Showing
2 changed files
with
75 additions
and
60 deletions.
There are no files selected for viewing
105 changes: 45 additions & 60 deletions
105
src/main/java/com/thealgorithms/maths/NonRepeatingElement.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
*/ | ||
} |
30 changes: 30 additions & 0 deletions
30
src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TestData> 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})); | ||
} | ||
} |