refactor: NonRepeatingElement (#5375)

This commit is contained in:
Alex Klymenko
2024-08-24 15:08:22 +02:00
committed by GitHub
parent a7cd97d75e
commit b231a72d44
2 changed files with 80 additions and 65 deletions

View File

@ -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];
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
for (i = 0; i < n; i++) {
res ^= arr[i];
}
// Finding the rightmost set bit
res = res & (-res);
int num1 = 0;
int num2 = 0;
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
}
}
System.out.println("The two non repeating elements are " + num1 + " and " + 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.
/**
* 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");
}
int xorResult = 0;
// Find XOR of all elements
for (int num : arr) {
xorResult ^= num;
}
// 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;
}
}
return new int[] {num1, num2};
}
}