📜  阵列中任何对的OR和AND的最小XOR(1)

📅  最后修改于: 2023-12-03 15:42:23.579000             🧑  作者: Mango

题目介绍

给定一个长度为 $n$ 的数组 $a_1,a_2,\cdots,a_n$,求最小的 $x$($0 \leq x < 2^{30}$),使得存在两个下标 $i,j$ 满足 $1 \leq i < j \leq n$ 且 $(a_i \operatorname{or} a_j) \operatorname{xor} x$ 最小,其中 $\operatorname{and}$ 表示按位与,$\operatorname{or}$ 表示按位或,$\operatorname{xor}$ 表示按位异或。

算法思路

暴力做法是枚举所有 $i,j$ 的组合,然后计算他们的 $\operatorname{or}$ 和 $\operatorname{xor}$,最后取最小值。这种做法有 $O(n^2)$ 个组合,因此时间复杂度为 $O(n^2)$。

更加优秀的做法是线性扫描。我们从最高位(第 $30$ 位)开始,枚举当前位为 $0$ 或 $1$ 时,对于数组中的每一个数,看它在这一位上是否为 $0$ 或 $1$。将所有当前位为 $1$ 的数存入一个集合 $S_1$ 中,将所有当前位为 $0$ 的数存入一个集合 $S_0$ 中。如果 $S_0$ 和 $S_1$ 都非空,那么当前位为 $1$,否则当前位为 $0$。如果当前位为 $1$,那么最小的 $x$ 中这一位为 $1$,否则最小的 $x$ 中这一位为 $0$。在做完所有 $30$ 位后,我们得到了最小的 $x$。

时间复杂度为 $O(n\log n)$。

代码实现
def solve(n: int, a: List[int]) -> int:
    ans = 0
    for k in range(30, -1, -1):
        s0, s1 = set(), set()
        for i in range(n):
            if (a[i] >> k) & 1:
                s1.add(a[i])
            else:
                s0.add(a[i])
        if s0 and s1:
            ans |= 1 << k
    return ans
参考资料