AlgoMaster Logo

Maximum XOR of Two Numbers in an Array

Last Updated: March 29, 2026

medium
5 min read

Understanding the Problem

We need to pick two numbers from the array (they can be the same element, since i can equal j) and XOR them together, then return the largest XOR result possible across all pairs.

XOR (exclusive or) compares corresponding bits of two numbers. If the bits differ, the result bit is 1. If they match, it's 0. So to maximize the XOR, we want two numbers whose binary representations differ in as many high-order bit positions as possible. A 1 in bit position 30 is worth more than having 1s in every position from 0 to 29 combined, so the strategy is greedy: try to make the highest bit a 1 first, then the next highest, and so on.

This "maximize bit by bit from the top" thinking is the key observation that drives both optimal approaches.

Key Constraints:

  • 1 <= nums.length <= 2 * 10^4 → With n up to 20,000, an O(n^2) brute force would perform up to 400 million operations. That's borderline and might TLE depending on constant factors. We should aim for something better.
  • 0 <= nums[i] <= 2^31 - 1 → Values are non-negative 32-bit integers. This means at most 31 bits to consider. Any approach that iterates over bits adds a factor of at most 31, which is essentially constant.

Approach 1: Brute Force

Intuition

The simplest idea: try every pair. For each pair (i, j), compute nums[i] XOR nums[j] and track the maximum. No clever tricks, just exhaustive search.

XOR is cheap to compute (a single CPU instruction), so even though we're checking O(n^2) pairs, each check is fast. For small arrays this is perfectly fine.

Algorithm

  1. Initialize maxXor = 0.
  2. For each index i from 0 to n-1, for each index j from i to n-1, compute nums[i] XOR nums[j].
  3. Update maxXor if the current XOR is larger.
  4. Return maxXor.

Example Walkthrough

1Start: check all pairs. i=0, j=0: 3 XOR 3 = 0, maxXor=0
0
i
3
j
1
10
2
5
3
25
4
2
5
8
1/5

Code

The brute force checks all O(n^2) pairs without leveraging the bit structure of XOR. What if we could build the answer one bit at a time, checking at each level whether a given bit can be set to 1?

Approach 2: Bitwise Prefix with Hash Set

Intuition

Here's the key insight: we can build the maximum XOR one bit at a time, from the most significant bit (MSB) down to the least significant bit (LSB).

At each bit position, we ask: "Can we set this bit to 1 in our answer?" If yes, we keep it. If no, we leave it as 0 and move on to the next bit.

But how do we check whether a particular bit can be set? This is where a clever XOR property comes in: if a XOR b = c, then a XOR c = b. So if we want to know whether there exist two numbers in the array whose XOR has a certain prefix, we can store all the prefixes in a hash set, then for each prefix p, check whether p XOR candidateAnswer exists in the set. If it does, two numbers can produce that candidate answer.

Algorithm

  1. Initialize maxXor = 0.
  2. For each bit position k from 30 down to 0 (since max value is 2^31 - 1, bit 30 is the highest that can be set):

a. Compute candidate = maxXor | (1 << k) — this is the best answer so far with bit k tentatively set to 1.

b. Extract the prefix of each number by right-shifting by k bits: prefix = num >> k for every num. Store all prefixes in a hash set.

c. For each prefix p in the set, check if p XOR (candidate >> k) also exists in the set.

d. If yes, set maxXor = candidate (we confirmed bit k can be 1).

e. If no prefix pair produces the candidate, maxXor stays unchanged (bit k remains 0).

  1. Return maxXor.

Example Walkthrough

1Start: nums in binary: [00011, 01010, 00101, 11001, 00010, 01000]. maxXor=0
0
3
1
10
2
5
3
25
4
2
5
8
1/6

Code

The hash set approach is already O(n) but involves rebuilding the set 31 times with hash overhead. What if we stored all numbers in a binary trie and walked it greedily, choosing the opposite bit at every step?

Approach 3: Binary Trie (Optimal in Practice)

Intuition

Think of every number as a 31-bit binary string. If we insert all numbers into a trie where each node branches on 0 or 1, we get a binary trie that represents the entire array.

Now for each number, we want to find the number in the trie that maximizes the XOR with it. Since XOR produces a 1 when bits differ, at each level of the trie we greedily choose the opposite bit if possible. If the current number has a 0 at bit k, we try to go down the 1-branch of the trie (and vice versa). If the opposite branch doesn't exist, we're forced to take the same-bit branch (which contributes 0 to the XOR at that position).

This greedy walk through the trie for each number gives us the maximum XOR partner in O(31) time per number.

Algorithm

  1. Build a binary trie: for each number in the array, insert its binary representation (31 bits, from MSB to LSB) into the trie.
  2. For each number in the array, traverse the trie greedily:

a. At each bit position (from bit 30 down to 0), check the current bit of the number.

b. Try to go to the child with the opposite bit (this maximizes XOR at this position).

c. If the opposite child doesn't exist, go to the same-bit child.

d. Accumulate the XOR result based on which path was taken.

  1. Track the maximum XOR across all numbers.
  2. Return the maximum.

Example Walkthrough

1All numbers inserted into binary trie. Now query each for best XOR partner.
0
3
1
10
2
5
3
25
4
2
5
8
1/7

Code