这个题最开始想到的就是O(N^2)的做法,但是显然不满足要求,后来又从最大最小值入手考虑,但是没发现具体规律。
最后看了后面别人的做法,开始没太看懂,后来花费了点时间才搞懂了。贴上别人的代码和自己的理解
package leetcode;
import java.util.HashSet;
import java.util.Set;
public class MaximumXOR {
//1、利用字典树
class Trie {
Trie[] children;
public Trie() {
children = new Trie[2];
}
}
public int findMaximumXOR(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
// Init Trie.构造字典树
Trie root = new Trie();
for(int num: nums) {
Trie curNode = root;
for(int i = 31; i >= 0; i --) {
int curBit = (num >>> i) & 1;
if(curNode.children[curBit] == null) {
curNode.children[curBit] = new Trie();
}
curNode = curNode.children[curBit];
}
}
int max = Integer.MIN_VALUE;
for(int num: nums) {
Trie curNode = root;
int curSum = 0;
for(int i = 31; i >= 0; i --) {
int curBit = (num >>> i) & 1;
/*
* curBit ^ 1 相当于curBit的反码,只有尽可能的匹配数字的反码
* 得到的结果才是最大的,因为与反码 ^ 得到的结果是1
*/
if(curNode.children[curBit ^ 1] != null) {
curSum += (1 << i);
curNode = curNode.children[curBit ^ 1];
}else {
curNode = curNode.children[curBit];
}
}
max = Math.max(curSum, max);
}
return max;
}
//2、用set集合
public int findMaximumXOR1(int[] nums) {
int max = 0;
int mask = 0;
for(int i = 31; i >= 0; i--) {
mask = mask | (1 << i);//用mask从左到右提取前缀
/*mask的变化情况
* 10000000...
* 11000000...
* 11100000...
* 11110000...
* 11111000...
* ....
*/
Set<Integer> set = new HashSet<Integer>();
for(int num : nums) {
set.add(num & mask);//将数组中每个数的相应前缀提取出来,放到set里面
}
/*
* res代表当前情况可能的最大值。比如说max是10000...
* 则res就是11000...,如果后面res可以得到,那就说明res这种情况存在
* 就是最大值,将其赋给max。
*/
int res = max | (1 << i);
for(int premix : set) {
/*
* 这里用到一个性质,如果a ^ b = c, 则 a = c ^ b;
* 如果说res^premix在set集合中,则说明set中有两个数异或可以得到res
* 将res赋值给max.
*/
if(set.contains(premix^res)) {
max = res;
break;
}
}
}
return max;
}
}