LeetCode 421数组中两个数的最大异或值
题目描述
给定一个非空数组,数组中元素为 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.
解题
暴力法就是计算所有两两异或的结果,求最大值。那如何减少运算量呢?首先我们知道的是高位的异或结果比低位更重要,因此我们应该从最高位开始比较异或结果。其次异或运算有个特点:
c = a ^ b ⇔ b = c ^ a ⇔ a = c ^ b
因此,对于前N位,我们可以知道能得到的最大异或结果,如果数组中存在两个数的前N位异或结果等于这个当前最大结果等价于数组中存在一个等于当前数字前N位与当前最大的异或结果的数字,这样两两计算转化为m次的计算和查找,m为数组的大小。查找的过程我们可以借助哈希表:
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int max_num = nums[0];
for (auto i : nums){
max_num = max_num < i ? i : max_num;
}
int bitnum=0;
while(max_num){
++bitnum;
max_num >>= 1;
}
unordered_set<int> temp_nums;
int cur_max, maxXOR=0, temp_val;
while (bitnum--){
maxXOR <<= 1;
cur_max = maxXOR | 1;
temp_nums.clear();
for (auto i : nums) {
i >>= bitnum;
if (temp_nums.find(i ^ cur_max)!= temp_nums.end()){
maxXOR = cur_max;
break;
}
temp_nums.emplace(i);
}
cur_max << 1;
}
return maxXOR;
}
};
上述方法中依然存在计算冗余,比如在计算前N位异或结果时,可能某些数字的前N位无法得到当前最大的异或结果,但是在计算N+1位时还是参与了计算,借助树结构就可以避免这些多余的计算过程。
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int max_num = nums[0], bit_num=0;
for(auto i:nums){
max_num = max_num < i ? i : max_num;
}
while (max_num){
++bit_num;
max_num >>= 1;
}
root = new Node;
int maxXOR=0, cur_XOR;
for (auto i:nums){
cur_XOR = cal_maxXOR(i, bit_num);
maxXOR = maxXOR < cur_XOR ? cur_XOR : maxXOR;
}
return maxXOR;
}
private:
struct Node{
Node *childs[2] = {NULL};
}*root;
int cal_maxXOR(int i, int bit_num){
Node *cur_node1 = root;
Node *cur_node2 = root;
int maxXOR=0;
while (bit_num--){
maxXOR <<= 1;
int index = (i>>bit_num)&1;
if (cur_node1->childs[index] == NULL)
cur_node1->childs[index] = new Node;
cur_node1 = cur_node1->childs[index];
if (cur_node2->childs[1-index]){
cur_node2 = cur_node2->childs[1-index];
maxXOR += 1;
}
else{
cur_node2 = cur_node2->childs[index];
}
}
return maxXOR;
}
};