Loading...

数组中两个数的最大异或值

在这里插入图片描述

求解思路

要让异或结果尽可能大,就要让高位尽可能出现1。

我们可以从最高位开始贪心,每一位都尝试让结果为1。

具体来说就是,先找到数组中最大值确定需要考虑的最高位,然后有2种解法:

第1种是用前缀树存储所有数字的二进制表示,查询时对于每个数字从高位到低位贪心地选择相反的路径(即当前位是0就找1,是1就找0),这样能保证异或结果尽可能大;

第2种是用哈希表,从高位到低位逐位确定答案,每次尝试在当前答案基础上让下一位为1,通过哈希表快速判断是否存在两个数能达成这个目标。

方法1:前缀树解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public static int findMaximumXOR(int[] nums) {
    build(nums);
    int ans = 0;
    for (int num : nums) {
        ans = Math.max(ans, maxXor(num));
    }
    clear();
    return ans;
}

public static int MAXN = 3000001;
public static int[][] tree = new int[MAXN][2];
public static int cnt;
public static int high;

public static void build(int[] nums) {
    cnt = 1;
    int max = Integer.MIN_VALUE;
    for (int num : nums) {
        max = Math.max(num, max);
    }
    // 计算最高有效位,忽略前导零
    high = 31 - Integer.numberOfLeadingZeros(max);
    for (int num : nums) {
        insert(num);
    }
}

public static void insert(int num) {
    int cur = 1;
    for (int i = high, path; i >= 0; i--) {
        path = (num >> i) & 1;
        if (tree[cur][path] == 0) {
            tree[cur][path] = ++cnt;
        }
        cur = tree[cur][path];
    }
}

public static int maxXor(int num) {
    int ans = 0;
    int cur = 1;
    for (int i = high, status, want; i >= 0; i--) {
        status = (num >> i) & 1;
        want = status ^ 1;  // 期望遇到相反的位
        if (tree[cur][want] == 0) {
            want ^= 1;  // 如果不存在则走相同的位
        }
        ans |= (status ^ want) << i;
        cur = tree[cur][want];
    }
    return ans;
}

public static void clear() {
    for (int i = 1; i <= cnt; i++) {
        tree[i][0] = tree[i][1] = 0;
    }
}

方法2:哈希表解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int findMaximumXOR(int[] nums) {
    int max = Integer.MIN_VALUE;
    for (int num : nums) {
        max = Math.max(num, max);
    }
    int ans = 0;
    HashSet<Integer> set = new HashSet<>();
    for (int i = 31 - Integer.numberOfLeadingZeros(max); i >= 0; i--) {
        int better = ans | (1 << i);  // 尝试让第i位为1
        set.clear();
        for (int num : nums) {
            num = (num >> i) << i;  // 保留高位,低位清零
            set.add(num);
            // 如果存在 better ^ num,说明可以达成better
            if (set.contains(better ^ num)) {
                ans = better;
                break;
            }
        }
    }
    return ans;
}
最后更新于 2026-04-05 17:35:33
Code Road Record