前言
异或运算,相当于二进制数的不进位加法:两位相同结果为0,两位不同结果为1。这道题目求一些整数中的两个数,这两个数的异或值为这些数两两异或结果的最大值。解决方法的数据结构用到Trie树,算法主要是Trie树的构建,以及针对Trie树的查询。
一、题目陈述

二、解决思路
1.暴力解决
可以通过两重循环来解决,复杂度显然是O(N*N),而C++ 1秒能大概算1 0 7 10^7107~1 0 8 10^8108,相对于题目的规模显然不能使用。
2.数字变为二进制存储统计的思考
我们想要求一个数a的匹配数b,这个数b和a的异或结果最大,自然是希望从最高位开始,数b的每一位都和数a相异。自然想到,可以用Trie树来存储每一个数的二进制表示,然后从高位查询异或和最大的数。即用一个Tire树来存下N个数的二进制形式的01串,串的长度是30,因为每个数最多不超过2^31所以,取30。然后根据异或的特性,枚举一下所有的数,取这个数每一位的反码,去树中寻找尽可能和反码向同的路径,并且记录下路径过程的异或结果即可。复杂度是O(N*logN)。
三、代码实现
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010 , M=31*N;
int n;
int a[N];
// Trie树的数据结构
int trie[M][2],idx;
void insert(int x) {
/*
将x的二进制表示插入Trie树中
*/
int p=0;
for(int i=30;i>=0;i--) {
// 取出x的第i位数
int u=x>>i&1;
if(!trie[p][u]) trie[p][u] = ++idx;
p = trie[p][u];
}
}
int query(int x) {
/*
返回与目前Trie树中,与x异或和最大的数
*/
int p=0;
// res是与x异或和最大的数
int res=0;
for(int i=30;i>=0;i--) {
// 取出x的第i位
int u=x>>i&1;
if(trie[p][!u]) {
p=trie[p][!u];
res = res*2+!u;
}
else {
p=trie[p][u];
res=res*2+u;
}
}
return res;
}
int main() {
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int res = 0;
for(int i=0;i<n;i++) {
// 先插入再查询 目的是解决边界问题,最开始还没有存储任何一个数
insert(a[i]);
int t=query(a[i]);
res = max(res,a[i]^t);
}
cout<<res<<endl;
return 0;
}
总结
这道题是2021寒假第一题,也是刷题笔记系列的第一篇。主要用的思想是将数的二进制表示使用Trie树存储,然后进行查询。
版权声明:本文为weixin_43681549原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。