mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-08 02:04:31 +08:00
refactor: NonRepeatingElement
(#5375)
This commit is contained in:
@ -1,76 +1,61 @@
|
|||||||
package com.thealgorithms.maths;
|
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
|
* Reason to use bitwise operator: It makes our program faster as we are operating on bits and not
|
||||||
* on actual numbers.
|
* 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 {
|
public final class NonRepeatingElement {
|
||||||
private NonRepeatingElement() {
|
private NonRepeatingElement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
/**
|
||||||
try (Scanner sc = new Scanner(System.in)) {
|
* Finds the two non-repeating elements in the array.
|
||||||
int i;
|
*
|
||||||
int res = 0;
|
* @param arr The input array containing exactly two non-repeating elements and all other elements repeating.
|
||||||
System.out.println("Enter the number of elements in the array");
|
* @return An array containing the two non-repeating elements.
|
||||||
int n = sc.nextInt();
|
* @throws IllegalArgumentException if the input array length is odd.
|
||||||
if ((n & 1) == 1) {
|
*/
|
||||||
// Not allowing odd number of elements as we are expecting 2 non repeating
|
public static int[] findNonRepeatingElements(int[] arr) {
|
||||||
// numbers
|
if (arr.length % 2 != 0) {
|
||||||
System.out.println("Array should contain even number of elements");
|
throw new IllegalArgumentException("Array should contain an even number of elements");
|
||||||
return;
|
|
||||||
}
|
|
||||||
int[] arr = new int[n];
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find XOR of the 2 non repeating elements
|
int xorResult = 0;
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
res ^= arr[i];
|
// Find XOR of all elements
|
||||||
|
for (int num : arr) {
|
||||||
|
xorResult ^= num;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finding the rightmost set bit
|
// Find the rightmost set bit
|
||||||
res = res & (-res);
|
int rightmostSetBit = xorResult & (-xorResult);
|
||||||
int num1 = 0;
|
int num1 = 0;
|
||||||
int num2 = 0;
|
int num2 = 0;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
// Divide the elements into two groups and XOR them
|
||||||
if ((res & arr[i]) > 0) { // Case 1 explained below
|
for (int num : arr) {
|
||||||
num1 ^= arr[i];
|
if ((num & rightmostSetBit) != 0) {
|
||||||
|
num1 ^= num;
|
||||||
} else {
|
} else {
|
||||||
num2 ^= arr[i]; // Case 2 explained below
|
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.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
@ -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}));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user