📅  最后修改于: 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