最大异或对
1.题目
在给定的 N个整数 A~1~,A~2~......A~N~ 中选出两个进行 xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 N。
第二行输入 N 个整数 A1~AN。
输出格式
输出一个整数表示答案。
数据范围
1 ≤ N ≤ 1 0 5 , 1≤N≤10^5, 1≤N≤105,
0 0 0≤ A i Ai Ai<2^31
输入样例:
3
1 2 3
输出样例:
3
2.基本思想
-
1.son数组定义是二维数组,
son[n][m]
,可以先理解它的第二维度,只有两种状态0/1,是因为这一位表示的是某个数字的的某一位是0 / 1,而第一维的大小是我们用的十位二进制表示下一共有多少位数,在本题中,数字一共有N个数字,N是小于10^5
的,一个数在int下是32
位,则我们需要至多3200000
的一维坐标,而p = son[n][0] / p = son[n][1]
其实存的值就是他的两个子节点的一维坐标的值。那么
x >> i & 1
其实就是我想知道x的二进制表示中的第i位(二进制位从第0位开始表示第0位 - 第 31 位),本题的题目范围到2^31
那么就是i从30 - 0
。 -
2.构建逻辑其实相对简单,就是将数的二进制表示插入到
son
数组中,如果没有那么就将他的值附上++idx
即可 -
3.查询的时候为了异或大小最大,那么就应该从根节点开始遍历最高位开始尽量让异或结果为
1
,在遍历查询数字的第i位的时候取第i
位的值为s
,查看son[p][!s]
是否存在,如果存在那么将res+= i << i
(这一位异或存在最大值为1),如果没有那么就让p = son[p][s]
。
3.代码实现
csharp
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main {
static int N = 3000010;
static int[][] son = new int[N][2];
static int idx;
static int[] a = new int[N];
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
insert(a[i]);
}
int res = 0;
for (int i = 0; i < n; i++) res = Math.max(res, query(a[i]));
System.out.println(res);
}
private static void insert(int x) {
int p = 0;
for (int i = 30; i >= 0; i--) {//从30开始枚举
int s = son[p][(x >> i) & 1];//看 x的二进制表示中 个位 是 0 还是 1
if (s == 0) son[p][(x >> i) & 1] = ++idx;//创建新节点
p = son[p][(x >> i)&1];
}
}
private static int query(int x) {
int res = 0, p = 0;
for (int i = 30; i >= 0; i--) {//从30开始枚举
int s = (x >> i) & 1;//看 x的二进制表示中 个位 是 0 还是 1
if (son[p][1 - s] != 0) {
res += (1 << i);
p = son[p][1 - s];
} else p = son[p][s];
}
return res;
}
}