Problem
You are given a sorted array of integers where every value appears exactly twice โ except for one value that appears exactly once. Find and return that unique element. Your solution must run in O(log n) time and use O(1) extra space.
- Input:
[1, 1, 2, 3, 3, 4, 4, 8, 8] - Output:
2 - Explanation: Every element except 2 appears twice; 2 is the unique single element.
Counter-example: [3, 3, 7, 7, 10, 11, 11] โ the pairs stop aligning at even indices after position 4, revealing that 10 at index 4 is the single element.
Intuition
Because every value appears twice, the pairs in the sorted array start out aligned at even indices (index 0 and 1, then 2 and 3, and so on). The single element breaks this alignment: everything to its right is shifted by one, so pairs now straddle odd/even boundaries. Binary search can detect this shift at any midpoint without scanning the entire array.
Approach 1 โ XOR Scan
XOR every number together. Paired values cancel out (x ^ x = 0), leaving only the single element (x ^ 0 = x). No sorting structure is exploited, but the code is remarkably short.
- Initialize
result = 0. - XOR every element in the array into
result. - Return
result.
1def singleNonDuplicate(nums: list[int]) -> int:
2 result = 0
3 for num in nums:
4 result ^= num # paired values cancel; only the unique one survives
5 return resultTime: O(n) โ visits every element once.
Space: O(1) โ only a single integer accumulator.
Approach 2 โ Binary Search on Pair Alignment
Before the single element, nums[even_index] == nums[even_index + 1]. After it, the pairing is off โ nums[even_index] != nums[even_index + 1]. Snap the midpoint to an even index and check which side of the boundary we are on.
- Set
lo = 0,hi = len(nums) - 1. - While
lo < hi: computemid; ifmidis odd, subtract 1 to make it even. - If
nums[mid] == nums[mid + 1], the pair atmidis intact โ single element is to the right, solo = mid + 2. - Otherwise, the pair is broken โ single element is at
midor to the left, sohi = mid. - Return
nums[lo].
1def singleNonDuplicate(nums: list[int]) -> int:
2 lo, hi = 0, len(nums) - 1
3 while lo < hi:
4 mid = (lo + hi) // 2
5 if mid % 2 == 1:
6 mid -= 1 # always evaluate at an even index so pair-check is meaningful
7 if nums[mid] == nums[mid + 1]:
8 lo = mid + 2 # pair is intact; single element lies further right
9 else:
10 hi = mid # pair broken here; single element is at mid or to its left
11 return nums[lo]Time: O(log n) โ halves the search space each iteration.
Space: O(1) โ only two pointers.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| XOR Scan | O(n) | O(1) | When the O(log n) constraint is not required; simpler and zero risk of pointer bugs |
| Binary Search | O(log n) | O(1) | When the problem explicitly requires sub-linear time, or the array is very large |
Common Mistakes
- Checking the wrong neighbor after adjusting
mid: After snappingmiddown to even, always comparenums[mid]withnums[mid + 1]โ comparing withnums[mid - 1]instead gives wrong results becausemid - 1may be the other half of a pair from the left region. - Setting
lo = mid + 1instead oflo = mid + 2: Whennums[mid] == nums[mid + 1], both indices belong to a complete pair that lies before the single element โ you must skip both, not just one. - Forgetting to snap
midto even: Ifmidis odd,nums[mid]is the second element of a pair. The pair-alignment rule (nums[even] == nums[even + 1]before the single element) only holds at even starting indices, so checking from an odd index gives a misleading result. - Accidentally going out of bounds: When
midis the last even index (e.g.,mid == len - 1),nums[mid + 1]would be out of bounds. Anchoringhito the last element and only snappingmiddown (never up) keepsmid + 1always valid whilelo < hi. - Applying XOR when O(log n) is required: XOR is elegant but O(n). If the interviewer specifies logarithmic time โ as this problem does โ the XOR solution will not be accepted even though it produces the correct answer.
Related Problems
Binary Searchโ foundational template this solution extendsFind Peak Elementโ binary search guided by a local structural property rather than a target valueFind Minimum in Rotated Sorted Arrayโ uses array structure (sorted with a rotation point) to decide which half to discardSearch in Rotated Sorted Arrayโ binary search where the invariant is not simple monotonicityKoko Eating Bananasโ binary search on a numeric property rather than an array position