题目描述:
给你一个整数数组
nums
,返回nums[i] XOR nums[j]
的最大运算结果,其中0 ≤ i ≤ j < n
。
本题有哈希表和字典树两种解法,这里着重记录一下字典树解法。
字典树在处理类似的题目上有着广泛的应用,基本思想是将一个数 num
的二进制表示存在树中。由于一个整型变量由 32 bit
表示,因此可以用高度为 32
的字典树进行存储。
下图以 4 bit
存储数字 11
为例,构建了一棵字典树。可以看到构建方法是从最高位开始,遇到 0
往左子树走,遇到 1
则往右子树走。
在代码中,当遍历到 nums[i]
时,先将 nums[0 ~ i-1]
都加入到字典树中,这样就能快速判断出 nums[0 ~ i-1]
中任意数与 nums[i]
异或能得到的最大值;当遍历到 nums[n-1]
时,就得到了数组中所有数两两异或的最大值了。
判断函数 check
的原理:以最高位为例,假设当前数 x
的最高位是 1
,如果字典树 root
的左子树不为空,说明树中至少存在一个数 y
的最高位是 0
,那么 x^y
的最高位必然是 1
,由此可知 x
与树中存储的值的最大异或值的最高位一定可以为 1
。其他位同理。
class Solution {
Trie root = new Trie();
static final int HIGH_BIT = 31;
// 将数字 num 加入到字典树中
public void add(int num) {
Trie cur = root;
for(int k = HIGH_BIT; k >= 0; k--) {
int bit = (num >> k) & 1;
if(bit == 0) {
if(cur.left == null) {
cur.left = new Trie();
}
cur = cur.left;
}
else {
if(cur.right == null) {
cur.right = new Trie();
}
cur = cur.right;
}
}
}
// 在当前的字典树条件下,num 能够异或得到的最大值
public int check(int num) {
Trie cur = root;
int x = 0;
for(int k = HIGH_BIT; k >= 0; k--) {
int bit = (num >> k) & 1;
if(bit == 0) {
if(cur.right != null) {
cur = cur.right;
x |= (1 << k);
} else {
cur = cur.left;
}
} else {
if(cur.left != null) {
cur = cur.left;
x |= (1 << k);
} else {
cur = cur.right;
}
}
}
return x;
}
public int findMaximumXOR(int[] nums) {
int ans = 0;
// 不断往字典树中加入值,并判断当前的最大异或值
for(int i = 1; i < nums.length; i++) {
add(nums[i - 1]);
ans = Math.max(ans, check(nums[i]));
}
return ans;
}
}
class Trie {
Trie left = null;
Trie right = null;
}