Loading problems...
TL;DR: The optimal solution utilizes the XOR bitwise operation to cancel out duplicate numbers in a single pass, leaving only the unique element.
The LeetCode 136 problem, titled "Single Number," presents a classic algorithmic challenge involving array processing and optimization. You are provided with a non-empty array of integers where every element appears exactly twice, except for one element which appears only once. The objective is to identify and return that single, unique number.
Crucially, the problem imposes strict constraints: the solution must run in linear time complexity, , and use only constant extra space, . This eliminates standard frequency-counting approaches that rely on auxiliary data structures.
A naive approach to solving the Single Number problem involves tracking the frequency of each element to identify the one that appears once. This is typically achieved using a Hash Map (or Hash Set).
Pseudo-code:
nums.Complexity Analysis:
Why it fails: While this brute force method satisfies the linear time requirement, it violates the constant space constraint. Allocating memory proportional to the input size is not permitted. Alternatively, a brute force approach using nested loops to compare every number with every other number would satisfy the space constraint () but fail the time constraint (), likely resulting in a Time Limit Exceeded (TLE) error on large inputs.
The transition from a brute force approach to the optimal solution requires understanding the mathematical properties of the XOR (Exclusive OR) operation, denoted as .
The XOR operation has three critical properties that make it the perfect tool for this problem:
Key Invariant: Because every number appears exactly twice except for one, if we XOR all numbers in the array together, the duplicate pairs will "annihilate" each other (become 0). The only remaining value will be the single number, effectively .
Visual Description:
Imagine a binary register initialized to 0. As the algorithm iterates through the array, the register updates its state by XORing its current value with the incoming number. When the algorithm encounters the first instance of a number (e.g., 5), specific bits in the register flip. When the second instance of 5 is encountered later in the array, the exact same bits flip again. Since XOR is its own inverse, flipping a bit twice restores it to its original state. Consequently, all bits affected by paired numbers return to 0, while the bits corresponding to the single number remain flipped.

Consider the input: nums = [4, 1, 2, 1, 2]
result = 00 ^ 4000 ^ 100 = 100result is now 4.4 ^ 1100 ^ 001 = 101result is now 5.5 ^ 2101 ^ 010 = 111result is now 7.7 ^ 1111 ^ 001 = 110result is now 6. (Notice how the bits for 1 have been reversed).6 ^ 2110 ^ 010 = 100result is now 4.4.The intermediate values (5, 7, 6) are transient states. The final state guarantees that 1 cancelled 1, 2 cancelled 2, and 4 remains.
Let the array be represented as a set of integers , where is the single number and all appear twice.
The algorithm computes the sequential XOR sum:
Due to the commutative and associative properties of XOR, we can rearrange the terms to group identical numbers:
Applying the self-inverse property ():
Applying the identity property ():
Thus, the algorithm is mathematically guaranteed to return the single number.
cppclass Solution { public: int singleNumber(vector<int>& nums) { int result = 0; // Iterate through the vector, applying XOR to the accumulator for (int num : nums) { result ^= num; } return result; } };
javaclass Solution { public int singleNumber(int[] nums) { int result = 0; // Iterate through the array, applying XOR to the accumulator for (int num : nums) { result ^= num; } return result; } }
pythonclass Solution: def singleNumber(self, nums: List[int]) -> int: result = 0 # Iterate through the list, applying XOR to the accumulator for num in nums: result ^= num return result
Time Complexity:
We iterate through the array nums exactly once. Each XOR operation takes constant time. Thus, the time complexity is linear with respect to the number of elements.
Space Complexity:
We use a single variable result to store the cumulative XOR sum. No additional data structures (arrays, hash maps, stacks) are allocated. The space usage remains constant regardless of the input size.
The "Bitwise XOR - Finding Single/Missing Number" pattern is highly reusable. Understanding how XOR cancels duplicates allows you to solve several related variations:
Why does the naive solution TLE or run out of memory?
Why not use arithmetic sums?
Why not sort the array first?
nums[i] == nums[i+1]).