Repository: TheAlgorithms/Java
Pull request #5375 (2024-08-23 21:18:41)

refactor: `NonRepeatingElement`
Improving javadocs.
Improving the code to make it more readable.
Adding additional tests to this algorithm.

<!--
Thank you for your contribution!
In order to reduce the number of notifications sent to the maintainers, please:
- create your PR as draft, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests,
- make sure that all of the CI checks pass,
- mark your PR as ready for review, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review
-->

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [x] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5375?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
Attention: Patch coverage is `94.59459%` with `2 lines` in your changes missing coverage. Please review.
> Project coverage is 46.57%. Comparing base [(`ce4eb55`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/ce4eb55e0e7c5216e2cba53217627f6bbe8b5083?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`6a53719`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/6a53719d4075ae03782946b6bbaf24f9bd362d16?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).

| [Files](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5375?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) | Patch % | Lines |
|---|---|---|
| [...a/com/thealgorithms/maths/NonRepeatingElement.java](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5375?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fcom%2Fthealgorithms%2Fmaths%2FNonRepeatingElement.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms#diff-c3JjL21haW4vamF2YS9jb20vdGhlYWxnb3JpdGhtcy9tYXRocy9Ob25SZXBlYXRpbmdFbGVtZW50LmphdmE=) | 84.61% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5375?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5375      +/-   ##
============================================
+ Coverage     46.26%   46.57%   +0.30%     
- Complexity     2866     2882      +16     
============================================
  Files           525      525              
  Lines         15410    15387      -23     
  Branches       2916     2910       -6     
============================================
+ Hits           7130     7167      +37     
+ Misses         7981     7920      -61     
- Partials        299      300       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5375?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
diff --git a/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java b/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java
index 5f1190d6..9c95ebde 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.
-     */
 }


Test patch:
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 00000000..5f35cfe6
--- /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<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}));
+    }
+}