🧠
Trie-Based Bitwise Solution
💡 This approach uses a binary trie (prefix tree) to store numbers bit by bit, allowing efficient queries to find the best XOR partner for each number.
Intuition
Insert all numbers into a trie representing bits from most significant to least. For each number, traverse the trie to greedily pick opposite bits to maximize XOR.
Algorithm
- Build a trie with all numbers inserted bit by bit from the 31st to 0th bit.
- For each number, traverse the trie to find the number that maximizes XOR by choosing opposite bits when possible.
- Keep track of the maximum XOR found during these traversals.
- Return the maximum XOR after processing all numbers.
💡 This approach is more complex due to the trie data structure but offers clear logic for maximizing XOR bitwise.
class TrieNode:
def __init__(self):
self.children = {}
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, num):
node = self.root
for i in range(31, -1, -1):
bit = (num >> i) & 1
if bit not in node.children:
node.children[bit] = TrieNode()
node = node.children[bit]
def findMaxXor(self, num):
node = self.root
max_xor = 0
for i in range(31, -1, -1):
bit = (num >> i) & 1
toggled_bit = 1 - bit
if toggled_bit in node.children:
max_xor |= (1 << i)
node = node.children[toggled_bit]
else:
node = node.children.get(bit)
return max_xor
def findMaximumXOR(nums):
trie = Trie()
for num in nums:
trie.insert(num)
max_xor = 0
for num in nums:
max_xor = max(max_xor, trie.findMaxXor(num))
return max_xor
# Driver code
if __name__ == '__main__':
nums = [3, 10, 5, 25, 2, 8]
print(findMaximumXOR(nums)) # Output: 28
Line Notes
class TrieNode:Define a node in the trie with children for bits 0 and 1.
def insert(self, num):Insert a number into the trie bit by bit from MSB to LSB.
def findMaxXor(self, num):Find the maximum XOR for num by traversing trie choosing opposite bits when possible.
max_xor = max(max_xor, trie.findMaxXor(num))Update global maximum XOR after checking each number.
for i in range(31, -1, -1):Traverse bits from most significant to least significant to find best XOR path.
import java.util.*;
class TrieNode {
TrieNode[] children = new TrieNode[2];
}
public class Solution {
TrieNode root = new TrieNode();
public void insert(int num) {
TrieNode node = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
if (node.children[bit] == null) {
node.children[bit] = new TrieNode();
}
node = node.children[bit];
}
}
public int findMaxXor(int num) {
TrieNode node = root;
int maxXor = 0;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
int toggledBit = 1 - bit;
if (node.children[toggledBit] != null) {
maxXor |= (1 << i);
node = node.children[toggledBit];
} else {
node = node.children[bit];
}
}
return maxXor;
}
public int findMaximumXOR(int[] nums) {
for (int num : nums) insert(num);
int maxXor = 0;
for (int num : nums) {
maxXor = Math.max(maxXor, findMaxXor(num));
}
return maxXor;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] nums = {3, 10, 5, 25, 2, 8};
System.out.println(sol.findMaximumXOR(nums)); // Output: 28
}
}
Line Notes
TrieNode[] children = new TrieNode[2];Each node has two children representing bits 0 and 1.
for (int i = 31; i >= 0; i--)Traverse bits from most significant to least significant to find best XOR path.
if (node.children[toggledBit] != null)Try to go opposite bit to maximize XOR at this bit position.
maxXor = Math.max(maxXor, findMaxXor(num));Update maximum XOR after querying trie for each number.
#include <iostream>
#include <vector>
using namespace std;
struct TrieNode {
TrieNode* children[2] = {nullptr, nullptr};
};
class Trie {
public:
TrieNode* root;
Trie() { root = new TrieNode(); }
void insert(int num) {
TrieNode* node = root;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
if (!node->children[bit]) {
node->children[bit] = new TrieNode();
}
node = node->children[bit];
}
}
int findMaxXor(int num) {
TrieNode* node = root;
int maxXor = 0;
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
int toggledBit = 1 - bit;
if (node->children[toggledBit]) {
maxXor |= (1 << i);
node = node->children[toggledBit];
} else {
node = node->children[bit];
}
}
return maxXor;
}
};
int findMaximumXOR(vector<int>& nums) {
Trie trie;
for (int num : nums) trie.insert(num);
int maxXor = 0;
for (int num : nums) {
maxXor = max(maxXor, trie.findMaxXor(num));
}
return maxXor;
}
int main() {
vector<int> nums = {3, 10, 5, 25, 2, 8};
cout << findMaximumXOR(nums) << endl; // Output: 28
return 0;
}
Line Notes
TrieNode* children[2] = {nullptr, nullptr};Each trie node has two children for bits 0 and 1.
for (int i = 31; i >= 0; i--)Traverse bits from most significant to least significant to find best XOR path.
if (node->children[toggledBit])Try to go opposite bit to maximize XOR at this bit position.
maxXor = max(maxXor, trie.findMaxXor(num));Update maximum XOR after querying trie for each number.
class TrieNode {
constructor() {
this.children = {};
}
}
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(num) {
let node = this.root;
for (let i = 31; i >= 0; i--) {
const bit = (num >> i) & 1;
if (!(bit in node.children)) {
node.children[bit] = new TrieNode();
}
node = node.children[bit];
}
}
findMaxXor(num) {
let node = this.root;
let maxXor = 0;
for (let i = 31; i >= 0; i--) {
const bit = (num >> i) & 1;
const toggledBit = 1 - bit;
if (toggledBit in node.children) {
maxXor |= (1 << i);
node = node.children[toggledBit];
} else {
node = node.children[bit];
}
}
return maxXor;
}
}
function findMaximumXOR(nums) {
const trie = new Trie();
for (const num of nums) trie.insert(num);
let maxXor = 0;
for (const num of nums) {
maxXor = Math.max(maxXor, trie.findMaxXor(num));
}
return maxXor;
}
// Test
const nums = [3, 10, 5, 25, 2, 8];
console.log(findMaximumXOR(nums)); // Output: 28
Line Notes
this.children = {};Each trie node stores children for bits 0 and 1 as keys.
for (let i = 31; i >= 0; i--)Traverse bits from most significant to least significant to find best XOR path.
if (toggledBit in node.children)Try to go opposite bit to maximize XOR at this bit position.
maxXor = Math.max(maxXor, trie.findMaxXor(num));Update maximum XOR after querying trie for each number.
TimeO(n * log M)
SpaceO(n * log M)
Inserting n numbers into a trie with log M bits each takes O(n log M). Querying each number also takes O(log M). Space is O(n log M) for the trie nodes.
💡 For n=100000 and 32 bits, this is efficient but uses more memory than the prefix set approach.
Interview Verdict: Accepted
This approach is optimal and demonstrates mastery of tries and bit manipulation, useful for advanced interviews.