Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.
Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
Could you do this in O(n) runtime?
Example:
Input: [3, 10, 5, 25, 2, 8] Output: 28 Explanation: The maximum result is 5 ^ 25 = 28.
思路:按照位来算
/*
* 异或出来的结果就是31!种
* 实际上我们可以一个bit一个bit来,这样可以减少一点重复计算
* 比如11....是不行的,那么11..1..就不要算了
*/
public class Solution {
public int findMaximumXOR(int[] nums) {
int prefix = 0, max = 0;
for(int i=31; i>=0; i--) {
Set<Integer> set = new HashSet<Integer>();
prefix = prefix | (1<<i);
for(int num : nums)
set.add(num & prefix);
// 计算可能的更大值,基于以下定理:a^b^b=a,
// 如果set里面有2个数异或可以得到possibleMax,那么possibleMax和set里的一个数异或得到的就是set里面的另外一个数
int possibleMax = max | (1<<i);
for(int num : set)
if(set.contains(possibleMax ^ num)) {
max = possibleMax;
break;
}
}
return max;
}
}
Trie树版本
/*
* 需要两两比较,又是按照一位一位来计算的,所以考虑Trie
* 总体思路还是按位来算
*/
public class trie1 {
class Trie {
Trie[] children = new Trie[2];
}
public int findMaximumXOR(int[] nums) {
// build up Trie
Trie root = new Trie();
for(int num : nums) {
Trie cur = root;
for(int i=31; i>=0; i--) {
int bit = (num >> i) & i;
if(cur.children[bit] == null)
cur.children[bit] = new Trie();
cur = cur.children[bit];
}
}
// find bit by bit
int max = Integer.MIN_VALUE;
for(int num : nums) {
Trie cur = root;
int sum = 0;
for(int i=31; i>=0; i--) {
int bit = (num >> i) & i;
int xor = bit ^ 1;
if(cur.children[xor] != null) {
cur = cur.children[xor];
sum += (1 << i);
} else if(cur.children[bit] != null)
cur = cur.children[bit];
}
max = Math.max(max, sum);
}
return max;
}
}
用Object数组表示的Trie树版本
/*
* 新建Class Trie会超时
*/
public class Solution {
public int findMaximumXOR(int[] nums) {
// build up Trie
Object[] root = {null, null};
for(int num : nums) {
Object[] cur = root;
for(int i=31; i>=0; i--) {
int bit = (num >> i) & 1;
if(cur[bit] == null)
cur[bit] = new Object[]{null, null};
cur = (Object[]) cur[bit];
}
}
// find bit by bit
int max = Integer.MIN_VALUE;
for(int num : nums) {
Object[] cur = root;
int sum = 0;
for(int i=31; i>=0; i--) {
int bit = (num >> i) & 1;
int xor = bit ^ 1;
if(cur[xor] != null) {
cur = (Object[]) cur[xor];
sum += (1 << i);
} else if(cur[bit] != null)
cur = (Object[]) cur[bit];
}
max = Math.max(max, sum);
}
return max;
}
}
2刷:一般这样的bit运算都有个套路就是要按位来求,反正int就32位,
求到第i位时判断有没有2个数的前缀异或得到当前的最大值,想到了前缀,Trie树就自然而然想到了
/*
* 按位来求
* 求到第i位时判断有没有2个数的前缀异或得到当前的最大值
*/
public class Solution {
public int findMaximumXOR(int[] nums) {
int max = 0, prefix = 0;
for(int i=31; i>=0; i--) {
// 把前缀放到set里面
prefix = prefix | (1<<i);
Set<Integer> s = new HashSet<Integer>();
for(int num : nums) s.add(num & prefix);
int tmp = max | (1<<i);
for(int num : s)
if(s.contains(tmp ^ num)) { // 有2个前缀可以异或成当前可能的最大值
max = tmp;
break;
}
}
return max;
}
}