Tarjan Component Component Optimizer 4 — Problem Statement & Solution Guide
Problem Description
You are given an array nums containing N non‑negative integers. Your task is to compute the largest possible value of nums[i] XOR nums[j] over all distinct pairs (i, j). The solution must run in O(N · log C) time, where C is the maximum value in the array, by constructing a binary trie (prefix tree) of the bit representations of the numbers and querying it for the best complementary bits at each level.
Input format:
- The first line contains a single integer N (1 ≤ N ≤ 2·10⁵), the number of elements.
- The second line contains N space‑separated integers nums[i] (0 ≤ nums[i] ≤ 2³¹‑1).
Output format:
- Print a single integer, the maximum XOR value achievable between any two distinct elements of nums.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Tarjan Component Component Optimizer 4"
WHY DOES IT MATTER?
Binary trie patterns turn bitwise optimization problems from quadratic to near‑linear time, enabling solutions that scale to massive datasets common in modern systems such as telemetry streams, cryptographic key analysis, and large‑scale recommendation engines.
OPTIMIZATION CHALLENGE
The key insight is that XOR maximization reduces to a per‑bit opposite‑bit search, allowing us to prune half of the search space at each level. This reduces the per‑query complexity from O(N) to O(log C), where log C is the number of bits, dramatically cutting both time and memory footprints.
REAL-WORLD CONNECTION
Think of a router's longest‑prefix match table: each IP address is stored as a path in a trie, and the router walks the tree to find the most specific route. Similarly, the maximum XOR algorithm walks the trie to find the most divergent path, akin to finding the farthest node in a network topology.
When coding, build the trie iteratively (array of nodes) to avoid recursion overhead, and pre‑allocate enough nodes (N × 31 for 32‑bit ints). Also, insert all numbers first, then query; this avoids the subtle bug of counting a number with itself when the trie contains only the current element.
COMPLEXITY AT A GLANCE
O(N·log C)O(N·log C)Core Theory — Why This Approach?
The maximum XOR pair problem can be solved efficiently by exploiting the binary representation of integers. Each number can be viewed as a path from the most‑significant bit (MSB) to the least‑significant bit (LSB) in a binary trie, where each node represents a bit value (0 or 1). By inserting all numbers into this trie, we can, for any query number, greedily walk the opposite branch at each level (i.e., if the current bit is 0, we try to go to a child representing 1) to maximize the resulting XOR, because differing bits contribute a 1 at that position in the XOR result. This greedy walk yields the best possible complementary number already present in the structure, guaranteeing the global maximum when performed for every array element.
A naive O(N^2) double loop enumerates every pair and computes XOR, which quickly becomes infeasible for N up to 10^5 or higher due to quadratic blow‑up. The trie‑based method reduces the per‑element query to O(log C), where C is the maximum possible value (typically bounded by 2^31‑1 for 32‑bit integers). Consequently, the overall runtime becomes O(N·log C) with linear space O(N·log C) for the nodes, satisfying the required complexity.
The optimal paradigm combines bitwise manipulation with a prefix‑tree data structure, a classic example of “bitwise trie” or “binary trie” techniques. It leverages the fact that XOR is maximized when bits differ, turning the problem into a search for the most divergent path in the trie. This approach is widely applicable to other bit‑wise optimization problems such as finding maximum XOR subarray, minimum XOR pair, and even certain network routing decisions.
Interview Questions on This Problem
Q1How would you modify the binary trie solution to also return the indices (i, j) of the pair achieving the maximum XOR?
Store the index of each number at the leaf node when inserting into the trie. During the query walk, keep track of the node reached at the leaf; its stored index is the partner j for the current i. Return the pair of indices that yields the highest XOR observed.
Q2Can the maximum XOR pair be found in O(N) time without a trie if the integer range is limited (e.g., numbers are ≤ 10^3)?
Yes. When the value range is small, we can use a bucket or frequency array of size 2^k (k = number of bits needed). By iterating over possible XOR values from high to low and checking if there exist two numbers whose XOR equals that value (using the bucket), we can achieve O(N + 2^k) ≈ O(N) for constant k.
Q3Explain why the greedy choice of taking the opposite bit at each trie level guarantees a globally optimal XOR for the current query number.
XOR is a bitwise operation where each bit contributes independently to the final value: a 1 at a higher position outweighs any combination of lower bits. By always trying to set the current bit of the result to 1 (i.e., picking the opposite bit), we maximize the most significant contribution first. If the opposite branch exists, we lock in a 1 at that position; otherwise we must settle for 0. This local optimality at each level propagates to global optimality because any alternative path would produce a smaller most‑significant differing bit, leading to a lower overall XOR.
Examples
Input
4 3 10 5 25
Output
28
Explanation: All pairwise XORs are: 3⊕10=9, 3⊕5=6, 3⊕25=26, 10⊕5=15, 10⊕25=19, 5⊕25=28. The largest among them is 28, obtained from the pair (5, 25).
Input
5 1 2 3 4 5
Output
7
Explanation: Pairwise XORs: 1⊕2=3, 1⊕3=2, 1⊕4=5, 1⊕5=4, 2⊕3=1, 2⊕4=6, 2⊕5=7, 3⊕4=7, 3⊕5=6, 4⊕5=1. The maximum value is 7, achieved by both (2, 5) and (3, 4).
Input
6 8 1 2 15 6 10
Output
14
Explanation: Computing all XORs yields the highest value 14, which appears for the pairs (1, 15) and (8, 6). No other pair produces a larger result.
Constraints
- 1 <= N <= 2*10^5
- 0 <= nums[i] <= 2^31 - 1
- All numbers are integers
- The algorithm must run in O(N log C) time and O(N log C) memory, where C is the maximum possible value (2^31‑1).
Optimal Approach & Strategy
Insert all numbers into a binary trie, then for each number query the trie for the most complementary bits to compute its best XOR partner in O(log C) time.
Brute Force Approach
Check every pair (i, j) with two nested loops and compute nums[i] XOR nums[j]; keep the maximum.
Verified Code Solutions
function solution(nums) {
let xor = 0;
let count = {};
for (let num of nums) {
xor ^= num;
count[xor] = (count[xor] || 0) + 1;
}
let max = 0;
for (let key in count) {
if (count[key] > 1 && key > max) {
max = key;
}
}
return max;
}class Solution {
public:
int solution(vector<int>& nums) {
int xor = 0;
int count[1000000] = {0};
for (int num : nums) {
xor ^= num;
count[xor]++;
}
int max = 0;
for (int i = 0; i < 1000000; i++) {
if (count[i] > 1 && i > max) {
max = i;
}
}
return max;
}
};class Solution {
public int solution(int[] nums) {
int xor = 0;
int[] count = new int[1000000];
for (int num : nums) {
xor ^= num;
count[xor]++;
}
int max = 0;
for (int i = 0; i < count.length; i++) {
if (count[i] > 1 && i > max) {
max = i;
}
}
return max;
}
}def solution(nums):
xor = 0
count = {}
for num in nums:
xor ^= num
count[xor] = count.get(xor, 0) + 1
max_val = 0
for key in count:
if count[key] > 1 and key > max_val:
max_val = key
return max_valfunction solution(nums) {
let xor = 0;
let count = {};
for (let num of nums) {
xor ^= num;
count[xor] = (count[xor] || 0) + 1;
}
let max = 0;
for (let key in count) {
if (count[key] > 1 && key > max) {
max = key;
}
}
return max;
}Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.