题目描述:
给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在O(n)的时间解决这个问题吗?
示例:
输入: [3, 10, 5, 25, 2, 8]
输出: 28
解释: 最大的结果是 5 ^ 25 = 28.
如果使用的复杂度位O(n ^ 2)那么很简单,但是如果使用的是O(n)的时间复杂度就很难了,没整出来
考虑使用前缀树,第一遍将每个数字分解成从31位到0位的二进制,0放在左边,1放在右边,第二次遍历取出n判断是0还是1如果是0找该位是0的有没有有的话节点变换,如果是1那么同样的我们找0节点是否为空,最后我们进行异或。
直接上代码可能比较明显一些:
注意:判断某位上是0还是1需要先左移然后与之后判断是否
class Solution {
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public int findMaximumXOR(int[] nums) {
if(nums.length <= 1){
return 0;
}
TreeNode root = new TreeNode(-1);//作为根节点
for (int i : nums) {
TreeNode node = root;
// 将每个数字的二进制放入到root中去,0在左边,1在右边
// 为了简单起见最后的节点的左节点统一放该数字,便于最后的
// 异或
for (int j = 31; j >= 0; j--) {
if((i & (1 << j)) == 0){
// 放在左边
if(node.left == null){
node.left = new TreeNode(0);
}
node = node.left;
}else {
// 放在右边
if(node.right == null){
node.right = new TreeNode(1);
}
node = node.right;
}
// 最后放入的是该数字
}
node.left = new TreeNode(i);
}
int max = 0;
for(int n: nums) {
TreeNode node = root;
for(int i=31; i>=0; i--) {
if ((n & (1<<i)) == 0) {
if (node.right != null) {
node = node.right;
} else {
node = node.left;
}
} else {
if (node.left != null) {
node = node.left;
} else {
node = node.right;
}
}
}
int nn = node.left.val;
max = Math.max(max, n ^ nn);
}
return max;
}
}