Skip to content

Commit b231a72

Browse files
authored
refactor: NonRepeatingElement (#5375)
1 parent a7cd97d commit b231a72

File tree

2 files changed

+75
-60
lines changed

2 files changed

+75
-60
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,61 @@
11
package com.thealgorithms.maths;
22

3-
import java.util.Scanner;
4-
5-
/*
6-
* Find the 2 elements which are non repeating in an array
3+
/**
4+
* Find the 2 elements which are non-repeating in an array
75
* Reason to use bitwise operator: It makes our program faster as we are operating on bits and not
86
* on actual numbers.
7+
*
8+
* Explanation of the code:
9+
* Let us assume we have an array [1, 2, 1, 2, 3, 4]
10+
* Property of XOR: num ^ num = 0.
11+
* If we XOR all the elements of the array, we will be left with 3 ^ 4 as 1 ^ 1
12+
* and 2 ^ 2 would give 0. Our task is to find num1 and num2 from the result of 3 ^ 4 = 7.
13+
* We need to find the two's complement of 7 and find the rightmost set bit, i.e., (num & (-num)).
14+
* Two's complement of 7 is 001, and hence res = 1. There can be 2 options when we Bitwise AND this res
15+
* with all the elements in our array:
16+
* 1. The result will be a non-zero number.
17+
* 2. The result will be 0.
18+
* In the first case, we will XOR our element with the first number (which is initially 0).
19+
* In the second case, we will XOR our element with the second number (which is initially 0).
20+
* This is how we will get non-repeating elements with the help of bitwise operators.
921
*/
1022
public final class NonRepeatingElement {
1123
private NonRepeatingElement() {
1224
}
1325

14-
public static void main(String[] args) {
15-
try (Scanner sc = new Scanner(System.in)) {
16-
int i;
17-
int res = 0;
18-
System.out.println("Enter the number of elements in the array");
19-
int n = sc.nextInt();
20-
if ((n & 1) == 1) {
21-
// Not allowing odd number of elements as we are expecting 2 non repeating
22-
// numbers
23-
System.out.println("Array should contain even number of elements");
24-
return;
25-
}
26-
int[] arr = new int[n];
26+
/**
27+
* Finds the two non-repeating elements in the array.
28+
*
29+
* @param arr The input array containing exactly two non-repeating elements and all other elements repeating.
30+
* @return An array containing the two non-repeating elements.
31+
* @throws IllegalArgumentException if the input array length is odd.
32+
*/
33+
public static int[] findNonRepeatingElements(int[] arr) {
34+
if (arr.length % 2 != 0) {
35+
throw new IllegalArgumentException("Array should contain an even number of elements");
36+
}
2737

28-
System.out.println("Enter " + n + " elements in the array. NOTE: Only 2 elements should not repeat");
29-
for (i = 0; i < n; i++) {
30-
arr[i] = sc.nextInt();
31-
}
38+
int xorResult = 0;
3239

33-
// Find XOR of the 2 non repeating elements
34-
for (i = 0; i < n; i++) {
35-
res ^= arr[i];
36-
}
37-
38-
// Finding the rightmost set bit
39-
res = res & (-res);
40-
int num1 = 0;
41-
int num2 = 0;
40+
// Find XOR of all elements
41+
for (int num : arr) {
42+
xorResult ^= num;
43+
}
4244

43-
for (i = 0; i < n; i++) {
44-
if ((res & arr[i]) > 0) { // Case 1 explained below
45-
num1 ^= arr[i];
46-
} else {
47-
num2 ^= arr[i]; // Case 2 explained below
48-
}
45+
// Find the rightmost set bit
46+
int rightmostSetBit = xorResult & (-xorResult);
47+
int num1 = 0;
48+
int num2 = 0;
49+
50+
// Divide the elements into two groups and XOR them
51+
for (int num : arr) {
52+
if ((num & rightmostSetBit) != 0) {
53+
num1 ^= num;
54+
} else {
55+
num2 ^= num;
4956
}
50-
51-
System.out.println("The two non repeating elements are " + num1 + " and " + num2);
5257
}
58+
59+
return new int[] {num1, num2};
5360
}
54-
/*
55-
* Explanation of the code:
56-
* let us assume we have an array [1,2,1,2,3,4]
57-
* Property of XOR: num ^ num = 0.
58-
* If we XOR all the elemnets of the array we will be left with 3 ^ 4 as 1 ^ 1
59-
* and 2 ^ 2 would give
60-
* 0. Our task is to find num1 and num2 from the result of 3 ^ 4 = 7. We need to
61-
* find two's
62-
* complement of 7 and find the rightmost set bit. i.e. (num & (-num)) Two's
63-
* complement of 7 is 001
64-
* and hence res = 1. There can be 2 options when we Bitise AND this res with
65-
* all the elements in our
66-
* array
67-
* 1. Result will come non zero number
68-
* 2. Result will be 0.
69-
* In the first case we will XOR our element with the first number (which is
70-
* initially 0)
71-
* In the second case we will XOR our element with the second number(which is
72-
* initially 0)
73-
* This is how we will get non repeating elements with the help of bitwise
74-
* operators.
75-
*/
7661
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
5+
import java.util.stream.Stream;
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
public class NonRepeatingElementTest {
11+
12+
private record TestData(int[] input, int[] expected) {
13+
}
14+
15+
private static Stream<TestData> provideTestCases() {
16+
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}));
17+
}
18+
19+
@ParameterizedTest
20+
@MethodSource("provideTestCases")
21+
void testFindNonRepeatingElements(TestData testData) {
22+
int[] result = NonRepeatingElement.findNonRepeatingElements(testData.input);
23+
assertArrayEquals(testData.expected, result);
24+
}
25+
26+
@Test
27+
public void testFindNonRepeatingElementsWithLargeNumbers() {
28+
assertArrayEquals(new int[] {200000, 400000}, NonRepeatingElement.findNonRepeatingElements(new int[] {100000, 200000, 100000, 300000, 400000, 300000}));
29+
}
30+
}

0 commit comments

Comments
 (0)