📌  相关文章
📜  计算给定数组中按位 XOR 超过按位 AND 的对(1)

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

计算给定数组中按位 XOR 超过按位 AND 的对

问题描述

给定一个数组,计算其中所有数字两两组合的按位 XOR 值和按位 AND 值,并计算有多少对数字满足按位 XOR 值大于按位 AND 值。

解法

最朴素的想法是暴力枚举所有数字对并计算它们的按位 XOR 和按位 AND,然后统计大于小于的数量。这个做法的时间复杂度是 $O(n^2)$。

更好的做法是观察按位 XOR 和按位 AND 的定义,发现按位 XOR 和按位 AND 是对每一位进行独立的操作。因此,对于每一位,我们可以分别计算这一位的按位 XOR 和按位 AND,然后一起考虑,得到该位上满足条件的数字对数,最终求和即可。

具体来说,假设当前考虑的位是第 $i$ 位:

  • 令 $x$ 和 $y$ 分别表示两个数字在第 $i$ 位上的值,则该位上的按位 XOR 和按位 AND 分别可以表示为 $x_i \oplus y_i$ 和 $x_i & y_i$。
  • 因为 $\oplus$ 和 $&$ 都只有 $0$ 和 $1$ 两种取值,所以一共只有 $4$ 种情况,它们分别是 $00$、$01$、$10$ 和 $11$。
  • 对于全部的数字对中,只有满足 $x_i \oplus y_i = 1$ 的才可能有贡献,因为 $x_i \oplus y_i = 0$ 的都是按位 XOR 不大于按位 AND 的情况,不符合要求。
  • 对于 $x_i \oplus y_i = 1$ 的情况,只有当 $x_i = 0$ 且 $y_i = 1$ 或 $x_i = 1$ 且 $y_i = 0$ 时才有贡献,因为只有这两种情况下 $x_i & y_i = 0$;其他情况下 $x_i & y_i = 1$,不符合要求。

因此,我们只需要用 $4$ 个计数器分别统计每一种情况的数字对数目,然后根据上面的结论计算贡献即可。

时间复杂度 $O(32n)$,需要对每一位进行 $4$ 次计数,共 $32$ 位,因此每次计算的时间复杂度是 $O(4n)$。

代码实现
from typing import List

def count_pairs(arr: List[int]) -> int:
    n = len(arr)
    ans = 0
    for i in range(32):
        bit_xor_1 = bit_and_0 = 0  # x_i = 0, y_i = 1
        bit_xor_0 = bit_and_1 = 0  # x_i = 1, y_i = 0
        for x in arr:
            if x & (1 << i):
                bit_and_1 += 1
            if x & (1 << i) == 0:
                bit_and_0 += 1
            if x >> i & 1:
                bit_xor_1 += 1
            else:
                bit_xor_0 += 1
        # 等于 1 时才有贡献
        ans += bit_xor_1 * bit_and_0 + bit_xor_0 * bit_and_1
    return ans

时间复杂度 $O(32n)$,空间复杂度 $O(1)$。