🧠
Optimal XOR and Partition by Set Bit
💡 This approach uses XOR properties to find the two unique numbers in linear time and constant space. It is the most efficient and elegant solution, but requires understanding XOR and bit manipulation.
Intuition
XOR all numbers to get xor of the two unique numbers. Find a set bit in xor to partition numbers into two groups, each containing one unique number. XOR each group to find the unique numbers.
Algorithm
- XOR all numbers to get xor = num1 ^ num2, where num1 and num2 are unique.
- Find any set bit in xor (rightmost set bit) to differentiate num1 and num2.
- Partition numbers into two groups based on this set bit.
- XOR numbers in each group separately to get num1 and num2.
- Return the two unique numbers.
💡 This algorithm cleverly uses XOR to cancel duplicates and partitioning to separate unique numbers, achieving O(n) time and O(1) space.
from typing import List
def singleNumber(nums: List[int]) -> List[int]:
xor = 0
for num in nums:
xor ^= num
set_bit = xor & (-xor) # rightmost set bit
num1 = 0
num2 = 0
for num in nums:
if num & set_bit:
num1 ^= num
else:
num2 ^= num
return [num1, num2]
# Driver code
if __name__ == '__main__':
print(singleNumber([1,2,1,3,2,5])) # Output: [3,5]
Line Notes
xor = 0Initialize xor accumulator
for num in nums: xor ^= numXOR all numbers to get xor of two unique numbers
set_bit = xor & (-xor)Find rightmost set bit to partition numbers
if num & set_bitPartition numbers based on set bit
import java.util.*;
public class SingleNumberIII {
public static int[] singleNumber(int[] nums) {
int xor = 0;
for (int num : nums) {
xor ^= num;
}
int setBit = xor & (-xor); // rightmost set bit
int num1 = 0, num2 = 0;
for (int num : nums) {
if ((num & setBit) != 0) {
num1 ^= num;
} else {
num2 ^= num;
}
}
return new int[]{num1, num2};
}
public static void main(String[] args) {
int[] nums = {1,2,1,3,2,5};
int[] res = singleNumber(nums);
System.out.println(Arrays.toString(res)); // Output: [3, 5]
}
}
Line Notes
int xor = 0Initialize xor accumulator
for (int num : nums) { xor ^= num; }XOR all numbers to get xor of unique numbers
int setBit = xor & (-xor)Find rightmost set bit to partition numbers
if ((num & setBit) != 0)Partition numbers based on set bit
#include <iostream>
#include <vector>
using namespace std;
vector<int> singleNumber(vector<int>& nums) {
int xorVal = 0;
for (int num : nums) {
xorVal ^= num;
}
int setBit = xorVal & (-xorVal); // rightmost set bit
int num1 = 0, num2 = 0;
for (int num : nums) {
if (num & setBit) {
num1 ^= num;
} else {
num2 ^= num;
}
}
return {num1, num2};
}
int main() {
vector<int> nums = {1,2,1,3,2,5};
vector<int> res = singleNumber(nums);
cout << "[" << res[0] << ", " << res[1] << "]" << endl; // Output: [3, 5]
return 0;
}
Line Notes
int xorVal = 0;Initialize xor accumulator
for (int num : nums) { xorVal ^= num; }XOR all numbers to get xor of unique numbers
int setBit = xorVal & (-xorVal);Find rightmost set bit to partition numbers
if (num & setBit)Partition numbers based on set bit
function singleNumber(nums) {
let xor = 0;
for (const num of nums) {
xor ^= num;
}
const setBit = xor & (-xor); // rightmost set bit
let num1 = 0, num2 = 0;
for (const num of nums) {
if ((num & setBit) !== 0) {
num1 ^= num;
} else {
num2 ^= num;
}
}
return [num1, num2];
}
// Test
console.log(singleNumber([1,2,1,3,2,5])); // Output: [3,5]
Line Notes
let xor = 0;Initialize xor accumulator
for (const num of nums) { xor ^= num; }XOR all numbers to get xor of unique numbers
const setBit = xor & (-xor);Find rightmost set bit to partition numbers
if ((num & setBit) !== 0)Partition numbers based on set bit
We do a constant number of passes over the array, each O(n). No extra space besides variables.
💡 For n=100000, this means about 3 passes over the array, which is very efficient.
Interview Verdict: Accepted and optimal
This is the best approach for this problem, combining efficiency and elegance using bit manipulation.