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. 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 contributes 2^30, which exceeds the sum of 1s in every position from 0 to 29 combined (2^30 - 1). So the strategy is greedy: set the highest bit to 1 first if possible, then the next highest, and so on. That bit-by-bit reasoning drives both optimal approaches below.
1 <= nums.length <= 2 * 10^4 → With n up to 20,000, an O(n^2) brute force performs up to 400 million XOR-and-compare operations. That can pass with a fast constant factor, but the better approaches below run in O(n).0 <= nums[i] <= 2^31 - 1 → Values are non-negative 32-bit integers, so bit 30 is the highest bit that can be set, and we only consider bits 30 down to 0. Any approach that iterates over bits multiplies the cost by at most 31.Try every pair. For each pair (i, j), compute nums[i] XOR nums[j] and track the maximum across all pairs. XOR is a single machine instruction, so each of the O(n^2) checks is cheap, and this is enough for small arrays.
maxXor = 0.i from 0 to n-1, for each index j from i to n-1, compute nums[i] XOR nums[j].maxXor if the current XOR is larger.maxXor.The brute force ignores the bit structure of XOR. The next approach uses it to build the answer one bit at a time, in O(n).
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 whether that bit can be set to 1 in the answer. If yes, we keep it; if no, it stays 0 and we move to the next bit.
To check whether a bit can be set, we use the XOR identity: if a XOR b = c, then a XOR c = b. We work with prefixes, the high bits of each number down to the current bit position. Suppose the candidate answer has prefix candidatePrefix. If two numbers a and b produce it, then a XOR b = candidatePrefix, which rearranges to a XOR candidatePrefix = b. So we store every number's prefix in a hash set, and for each prefix p we test whether p XOR candidatePrefix is also in the set. A match means some pair achieves the candidate.
The greedy order from MSB to LSB is safe because bit k is worth 2^k, which exceeds the combined value of all lower bits (2^k - 1). So whenever bit k can be set, setting it produces a larger answer than any result that leaves it 0, no matter what the lower bits do. Committing to a confirmed high bit never blocks a better overall answer, so the final value is the global maximum.
maxXor = 0.k from 30 down to 0:candidate = maxXor | (1 << k), the best answer so far with bit k tentatively set to 1.prefix = num >> k.candidatePrefix = candidate >> k. For each prefix p in the set, check whether p XOR candidatePrefix is also in the set.maxXor = candidate (bit k is confirmed reachable). Otherwise maxXor is unchanged and bit k stays 0.maxXor.The hash set approach is O(n) but rebuilds the set 31 times and pays hash overhead on every lookup. The next approach stores all numbers once in a binary trie, then walks it greedily for each number, choosing the opposite bit at every step.
Represent every number as a 31-bit binary string and insert all of them into a trie where each node branches on a 0 or 1 child. Shared high-bit prefixes share the same path, so the trie compactly holds every number in the array.
To find the best XOR partner for a given number, walk down from the root one bit at a time. Since XOR produces a 1 when bits differ, at each level we take the child for the opposite bit when it exists: if the number has a 0 at bit k, we follow the 1-child, and vice versa. When the opposite child is missing, we follow the same-bit child, which contributes 0 to the XOR at that position. The path traced this way gives the maximum XOR partner for that number in 31 steps.
This greedy choice is optimal for the same reason as Approach 2: bit k is worth 2^k, which exceeds the sum of all lower bits, so taking a 1 at the highest available bit is never worse than any alternative. Repeating the walk for every number and keeping the largest result gives the answer.