题目描述
给定一个非空数组,数组中元素为 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.
分析
首先将所有数字都转化为2进制,我们可以发现这题有一个明显的贪心思想:要想两数异或值最大,则要尽可能使得两数在高位上相异。因此,当某数和其他数字在高位前缀上出现相异时,可以淘汰没有该前缀的其他数字。
因此想到可以构建字典树,然后基于贪心思想遍历字典树,每一步都选择尽可能使得高位相异的结果。
代码
class Solution {
private:
struct TrieNode
{
TrieNode* zero;
TrieNode* one;
TrieNode()
{
zero = NULL;
one = NULL;
};
};
TrieNode* root;
public:
int findMaximumXOR(vector<int>& nums) {
//构建字典树
root = new(TrieNode);
for(int i = 0; i < nums.size();i++)
{
TrieNode* p = root;
for(int b = 30; b >= 0;b--)
{
// 取2进制第b位上的内容
int bt = nums[i] >> b & 1;
if(bt == 1)
{
if(p->one == NULL)
{
p->one = new(TrieNode);
}
p = p->one;
}
else
{
if(p->zero == NULL)
{
p->zero = new(TrieNode);
}
p = p->zero;
}
}
}
int ans = 0;
// 每个数依次以贪心算法和字典树做异或
for(int i = 0; i < nums.size();i++)
{
int tmpVal = 0;
TrieNode* p = root;
for(int b = 30; b >= 0; b--)
{
// 取2进制第b位上的内容
int bt = nums[i] >> b & 1;
// 如果为1,则优先与0做异或;否则优先和1做异或
if(bt == 1)
{
if(p->zero != NULL)
{
tmpVal += 1 << b;
p = p->zero;
}
else
{
p = p->one;
}
}
else
{
if(p->one != NULL)
{
tmpVal += 1 << b;
p = p->one;
}
else
{
p = p->zero;
}
}
}
ans = max(ans,tmpVal);
}
return ans;
}
};