- Maximum XOR of Two Numbers in an Array
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.
我的代码
class Solution {
public int findMaximumXOR(int[] nums) {
if (nums.length == 0) {
return 0;
}
TrieNode root = new TrieNode();
// 建树
// 每一个数字循环32次,反正输入没有负数
// 从最高位开始处理
for (int i : nums) {
TrieNode node = root;
for (int j = 31; j >= 0; j--) {
int bit = (i >> j) & 1;
if (bit == 1) {
if (node.one == null) {// one的位置是null,就新建
node.one = new TrieNode();
}
node = node.one;
} else {
if (node.zero == null) {
node.zero = new TrieNode();
}
node = node.zero;
}
}
}
int max = Integer.MIN_VALUE;
//找每一个数字和别的数字异或出来的最大值!
//所有最大值,取其中最大的
for (int i : nums) {
TrieNode node = root;
int XOR = 0;// 异或结果,的累加。按位累加也是牛逼
for (int j = 31; j >= 0; j--) {
int bit = (i >> j) & 1;
//如果这一位是1,为了异或最大,最好使用0,这样异或出来是1
//如果0不存在就只能使用1,这样这一位异或出来就是0
//如果这一位是0,为了异或最大,最好使用1,这样异或出来是1
//如果1不存在就只能使用0,这样这一位异或出来就是0
if (bit == 1) {
if (node.zero != null) {
node = node.zero;
XOR += 1 << j;
} else {
node = node.one;
XOR += 0 << j;// 0没用为了明确还是写上
}
} else {
if (node.one != null) {
node = node.one;
XOR += 1 << j;
} else {
node = node.zero;
XOR += 0 << j;
}
}
}
max = max > XOR ? max : XOR;
}
return max;
}
}
class TrieNode {
TrieNode zero;
TrieNode one;
}
同样思路
trick: 通过预处理得到最大值的首位1,优化了Trie树的深度。
class Solution {
TreeNode root = new TreeNode(0);
public int findMaximumXOR(int[] nums) {
int max = findMax(nums);
int maxBit = 32 - Integer.numberOfLeadingZeros(max);
//build prefix tree
TreeNode currNode = root;
for (int i = 0; i < nums.length; i++) {
for (int j = maxBit -1; j >=0 ; j--) {
int tmp = (nums[i] >>j)& 1;
if(tmp == 0)
{
if(currNode.left == null)
{
currNode.left = new TreeNode(0);
}
currNode = currNode.left;
}else {
if(currNode.right == null)
{
currNode.right = new TreeNode(1);
}
currNode = currNode.right;
}
}
// finished for nums[i], will do it for nums[i++];
currNode = root;
}
//find max xor value
int maxXOR = 0;
for (int i = 0; i < nums.length; i++) {
int res = 0;
for (int j = maxBit -1; j >=0; j--) {
int tmp = (nums[i] >>j)& 1;
if(currNode.left != null && currNode.right != null)
{
if(tmp == 0)
{
currNode = currNode.right;
}else {
currNode = currNode.left;
}
}else {
currNode = currNode.left == null ? currNode.right : currNode.left;
}
res += (tmp^currNode.val) << j;
}
currNode = root;
maxXOR = maxXOR > res ? maxXOR : res;
}
return maxXOR;
}
private int findMax(int[] nums)
{
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
if(nums[i] > max)
{
max = nums[i];
}
}
return max;
}
private static class TreeNode{
int val;
TreeNode left,right;
TreeNode(int val)
{
this.val = val;
}
}
}
Bit maniputaipon
这个解法也是利用前缀树的思想,利用Map保存下一次遍历的前缀。(空间换时间)
贪心思想,从最大的bit到最小的bit组装最大异或值。
借用一段解释:
I think most people who find it hard to understand the code is stuck on this line if(set.contains(tmp ^ prefix))
The tricky part here is that we need to be aware of a key property of XOR applying on the above line: if A ^ B = C, then A ^ B ^ B = C ^ B, then A = C ^ B
Before executing that line, max stands for the maximum we can get if we consider only the most significant i - 1 bits, tmp stands for the potential max value we can get when considering the most significant i bits. How can we get this tmp? The only way we can get this value is that we have two values A and B in the set (a set of most significant i bits of each member), such that A ^ B equals to tmp. As mentioned earlier, A ^ B = tmp is equivalent to A = tmp ^ B. Here is where that line comes in: set.contains(tmp ^ B).
public class Solution {
public int findMaximumXOR(int[] nums) {
int max = 0, mask = 0;
for(int i = 31; i >= 0; i--){
mask = mask | (1 << i);
Set<Integer> set = new HashSet<>();
for(int num : nums){
set.add(num & mask);
}
int tmp = max | (1 << i);
for(int prefix : set){
if(set.contains(tmp ^ prefix)) {
max = tmp;
break;
}
}
}
return max;
}
}