We will use the concept of buckets, we want to make sure that two numbers that appear only once are stored in two different buckets.
We know all the other integer values in the array appear twice except the two integer numbers. So, if we do exor (^) of all the numbers in the array nums[]
then all the duplicates will become zero and the final result will be exor of two numbers that appear only once.
Once we have done the exor of all the numbers the resultant exor bit values will tell us that the bits that are set are the bits that differ in two integer values whose exor has been taken.
For example:
nums[] = [1,2,1,3,2,5] => 1 ^ 2 ^ 1 ^ 3 ^ 2 ^ 5 = 3^5 = 011 ^ 101 = 110 = 6.
Hence exor = 110;
note that the final exor has a 2nd and 3rd-bit set, which means 3,5 have different bits at these bit indexes.
Since, the exor set bits can tell the bit indexes at which the actual numbers differ, keeping this in mind, we don't have to know all the set bits we need first (either from right or from left).
To find the rightmost set bit we know we have a formula: val & (val-1) = result i.e result
is nothing but an integer value with right most bit of val
unset and all the other bits will remain the same in val
read more on how to unset the rightmost bit
When this result is exored (^) with the original value val
it gives an integer value with the right-most bit set.
Taking the same above example:
6 & 5 = 110 & 101 = 100 =4 = rightmostval
6 ^ 4 = 110 ^ 100 = 010 = 2
this 4 (rightmostval
) when exor with the original 6 (val
), it will give integer value with rightmost bit set = 2 = 010
Finally, this value 2 can be used to put two values( appearing once in the array) into two different buckets.
When 2 is & (and) with all the value in the nums[] array, it will either return 1 or 0.
we are only concerned about the two integer values( appearing once in the nums[] array i.e. 3 and 5 ), when 3 is & with 2 (rightmostvalue
) i.e. 110 & 011 = 1 put it in bucket 1, similarly 5 & 2 = 101 & 010 = 0 put it in bucket 2. (This happens because the 2 i.e.
is part of exor of 3^5 which is 6i.e.
this 2 helps segregate these two values 3 and 5).
Note, We don't have to worry about other values because they will either go in bucket 1 or bucket 2, and since they are duplicates they can be removed by doing simple ^(exor) of all the elements in bucket 1 and bucket 2.
In the end, Bucket 1 and Bucket 2 will be left with 3 and 5 only that can be returned as answers.
This is what is done in the below code:
Tc : O(2n)
Sc: O(1)
class Solution {
public int[] singleNumber(int[] nums) {
long exor = 0;
int once = 0;
int twos = 0;
for(int i =0;i<nums.length;i++){
exor = exor ^ nums[i];
}
int rightmost = (int) ( (exor & (exor-1)) ^ exor);
for(int i= 0;i<nums.length;i++){
if((rightmost & nums[i])!=0){
once = once ^ nums[i];
}
else{
twos = twos ^ nums[i];
}
}
return new int[]{once,twos};
}
}
Top comments (0)