题目
思路
如果找出数组中所有可能由两个数字组成的数对并求出它们的异或,通过比较就能得出最大的异
或值。这种直观的算法的时间复杂度是O(n ^ 2)
整数的异或有一个特点,如果两个相同数位异或的结果是0,那么两个相反的数位异或的结果为1。如果想找到某个整数k和其他整数的最大异或值,那么尽量找和k的数位不同的整数
因此这个问题可以转化为查找的问题,而且还是按照整数的二进制数位进行查找的问题。需要将整数的每个数位都保存下来。前缀树可以实现这种思路
前缀树的定义为:
static class Node {
Node[] next = new Node[2];
}
构建前缀树:即将每个数根据每一位是0还是1,从高位到低位放到前缀树中
private Node build(int[] nums) {
Node root = new Node();
for (int num : nums) {
Node cur = root;
for (int i = 31; i >= 0;i--) {
if (cur.next[(num >> i) & 1] == null) {
cur.next[(num >> i) & 1] = new Node();
}
cur = cur.next[(num >> i) & 1];
}
}
return root;
}
然后从高位开始扫描每个整数num的每个数位,如果前缀树中存在某个整数的相同位置的数位和num的数位相反,则优先选择这个相反的数位,这是因为两 个相反的数位异或的结果为1,比两个相同的数位异或的结果大
代码
class Solution {
static class Node {
Node[] next = new Node[2];
}
public int findMaximumXOR(int[] nums) {
Node root = build(nums);
int max = 0;
for (int num : nums) {
int xor = 0;
Node cur = root;
for (int i = 31;i>=0;i--) {
if (cur.next[1 - ((num >> i) & 1)] != null) {
xor = (xor << 1) + 1;
cur = cur.next[1 - ((num >> i) & 1)];
} else {
xor = (xor << 1);
cur = cur.next[((num >> i) & 1)];
}
}
max = Math.max(max,xor);
}
return max;
}
private Node build(int[] nums) {
Node root = new Node();
for (int num : nums) {
Node cur = root;
for (int i = 31; i >= 0;i--) {
if (cur.next[(num >> i) & 1] == null) {
cur.next[(num >> i) & 1] = new Node();
}
cur = cur.next[(num >> i) & 1];
}
}
return root;
}
}