题目
题目来源AcWing第143题
在给定的 N 个整数 A1,A2……AN 中选出两个进行 xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 N。
第二行输入 N 个整数 A1~AN。
输出格式
输出一个整数表示答案。
数据范围
1 ≤ N ≤ 105,
0 ≤ Ai <231
输入样例:
3
1 2 3
输出样例:
3
解题思路
首先可以很容易想到暴力枚举的办法
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
res = max(res, nums[i]^nums[j];
}
}
在暴力解法中找优化的方案,首先第一层循环要遍历一边数组显然优化不了。第二层优化的话就是找出与当前数异或最大的另一个数。
根据异或的特点,用trie树存储数据的二进制可以很快的找到异或值最大的点。树的每个节点最多有两个子树(0和1),查找是找相反的数就是异或的最大值了。
tire树方法代码(含详细注释)
#include <iostream>
using namespace std;
const int M = 3000010;
const int N = 100010;
int n, nums[N]; //n为数据个数,nums[]存放数据
int son[M][2]; //节点值为但钱节点序号,idx表示为第几个节点
int idx = 0; //son[M][2]构建trie树,M为父节点,[2]表示0或1
//将结点x插入trie树
void insect(int x){
int p = 0;//根节点
for(int i = 30; ~i; i--){//~i等同于i>=0
int &s = son[p][x >> i & 1]; //注意这里是取地址,不是赋值
if(!s) s = ++idx; //节点不存在的话创建节点并赋值
p = s;
}
}
//查询与x异或取最大的节点
int query(int x){
int p = 0, res = 0;
for(int i = 30; ~i; i--){
int s = x >> i & 1; //从高位开始取x的二进制数
if(son[p][!s]){ //当前位存在相反位,0对应1,1对应0
res += 1<<i; //在当前位上加0
p = son[p][!s];
}
else p = son[p][s];
}
return res;
}
int main(){
cin >> n;
for(int i = 0;i < n;i++){
cin >> nums[i];
insect(nums[i]);
}
int res = 0;//存结果
for(int i = 0;i < n;i++){
res = max(res,query(nums[i])); //更新结果,找最大值
}
cout << res << endl;
return 0;
}
结语
运用trie树解决问题的一个实例,理解trie树就要着理解父节点与子节点的联系,是怎么从树根走到树叶的。