Maximum XOR of Two Numbers in an Array
Given an integer array nums, return the maximum result of numsi XOR numsj, where 0 ≤ i ≤ j < n. Build the answer one bit at a time, from the highest bit down , greedily assuming each new bit can be set, then checking whether any two prefixes seen so far actually achieve it.
Constraints
- 1 ≤ nums.length ≤ 2 × 105
- 0 ≤ numsi ≤ 231 - 1
Example
nums = [3, 10, 5, 25, 2, 8]28Explanation 5 XOR 25 = 28 is the maximum XOR of any pair in the array.
In plain terms
- Bit prefix
- A number's leading bits down to some position, found by masking with the bits considered so far (num & mask) — comparing prefixes lets you check bit by bit without looking at the full numbers.
Greedily lock in each bit from the top down
nums = [3, 10, 5, 25, 2, 8]. Scanning from the highest relevant bit (bit 4, value 16) downward.
What happens in this step
maxXor = 0 mask = 0 nums (8-bit binary): 3 = 00000011 10 = 00001010 5 = 00000101 25 = 00011001 2 = 00000010 8 = 00001000 No number here has bit 5 or higher set, so mask stays empty and every prefix is 0 until bit 4 — the scan effectively starts there.
Steps to visualize
- Start with maxXor = 0 and go bit by bit from the highest bit to the lowest.
- Extend the mask to include the current bit, and collect every number's prefix under that mask.
- Tentatively assume this bit can be set in the answer: candidate = maxXor | (1 << bit).
- If any two collected prefixes XOR together to exactly candidate, keep it — that bit really is achievable.
- After the lowest bit, maxXor holds the maximum XOR of any pair.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
nums = [3, 10, 5, 25, 2, 8]. Scanning from the highest relevant bit (bit 4, value 16) downward.
What happens in this step
maxXor = 0 mask = 0 nums (8-bit binary): 3 = 00000011 10 = 00001010 5 = 00000101 25 = 00011001 2 = 00000010 8 = 00001000 No number here has bit 5 or higher set, so mask stays empty and every prefix is 0 until bit 4 — the scan effectively starts there.
Solution
function findMaximumXOR(nums) {
let maxXor = 0;
let mask = 0;
for (let bit = 31; bit >= 0; bit--) {
mask |= 1 << bit;
const prefixes = new Set();
for (const num of nums) {
prefixes.add(num & mask);
}
const candidate = maxXor | (1 << bit);
let found = false;
for (const prefix of prefixes) {
if (prefixes.has(candidate ^ prefix)) {
found = true;
break;
}
}
if (found) {
maxXor = candidate;
}
}
return maxXor;
}- Time
- O(32n) = O(n)
- Space
- O(n) for the prefix set at each bit
Test cases
| Input | Expected | Covers |
|---|---|---|
nums = [3, 10, 5, 25, 2, 8] | 28 | example from the docstring |
nums = [14, 70, 53, 83, 49, 91, 36, 80, 92, 51, 66, 70] | 127 | a larger array where the maximum XOR uses every low bit |
nums = [0, 0] | 0 | every value identical, so the best XOR is 0 |
nums = [2, 4] | 6 | smallest non-trivial input, exactly two elements |
nums = [8, 10, 2] | 10 | the maximum XOR involves the smallest and largest values, not the two largest |
nums = [1, 2, 3, 4, 5, 6, 7] | 7 | consecutive small integers where the max XOR comes from complementary low bits |