📜  给定数组中所有对的按位与之和(1)

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

给定数组中所有对的按位与之和

有一个长度为 $n$ 的非空数组,其中有 $a_0, a_1, ..., a_{n-1}$ 。

定义所有对 $(i, j)$ 的按位与(bitwise AND)之和为:

$$ \sum\limits_{0 \leq i < j < n} a_i \operatorname{and} a_j $$

其中 $\operatorname{and}$ 表示按位与运算。

你可以在数组的任意位置插入任意整数,以最大化对按位与之和的求和。

请编写一个函数,该函数接受一个整数数组,返回数组中所有对的按位与之和。

思路

因为要求对数组中的所有数按位与的和,所以我们需要让所有数的二进制的每一位都尽量都为 1,这样才能保证按位与的结果尽可能的大。

我们看最高位(首位)怎么计算:

假设数组中所有数二进制的最高位相同。将它们的最高位和次高位取出来比较,如果都是1,那么组成的数就是2。

如果有一个不是1,那么组成的数只能是1。

下面的例子比较简单,只是为了说明问题:

0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0

最高位都是0,从低位开始比较,发现第6位,4个数中只有第3个数该位是1,所以最高位的值为 1; 前6位都是1组成的二进制数为 001000,转为十进制数为8。

计算次高位:

重复上面的步骤,最后组成的二进制数为 001001。

以此类推,直至最后一位。

得到数组中所有数按位与结果的和。

代码
class Solution:
    def rangeBitwiseAnd(self, nums: List[int]) -> int:
        if not nums:
            return 0
        
        res, mask = 0, 1 << 30
        
        while mask > 0 and (nums[0] & mask) == 0:
            mask >>= 1
        
        while mask > 0:
            prev_bit = nums[0] & mask
            
            for n in nums[1:]:
                if (n & mask) != prev_bit:
                    mask >>= 1
                    return res
                
            res += mask
            mask >>= 1
        
        return res

代码中,我们仅需要对每个数字最大值的一位进行循环计算,如果当前值同时出现在当前位最大的两个数字中,那么就同时给结果加上该二进制位对应的数值。