📜  所有子数组的按位与之和(1)

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

所有子数组的按位与之和

在计算机科学中,"按位与"是指两个数字的二进制数位中,如果两个数字的相应位都是1,那么在这一位的结果为1,否则为0。"所有子数组的按位与之和"是指给定一个数组,计算该数组中所有子数组的按位与操作的结果之和。

例如,对于数组 [4, 8, 6, 2],其所有子数组为 [4],[8],[6],[2],[4, 8],[8, 6],[6, 2],[4, 8, 6],[8, 6, 2],[4, 8, 6, 2],它们的按位与结果分别是 4,8,6,2,0,0,2,0,0,0。因此,所有子数组的按位与之和为 4 + 8 + 6 + 2 + 0 + 0 + 2 + 0 + 0 + 0 = 22。

方法一

对于每个子数组,可以使用一个循环得到其中所有数的按位与值。这种方法的时间复杂度为 $O(N^3)$,其中 $N$ 是数组的长度。

def sum_of_all_subarrays(arr):
    result = 0
    for i in range(len(arr)):
        for j in range(i, len(arr)):
            bitwise_and = arr[i]
            for k in range(i + 1, j + 1):
                bitwise_and &= arr[k]
            result += bitwise_and
    return result
方法二

可以观察到,当某一位的二进制位上有一个0时,整个子数组的按位与操作的结果就为0,因为任何数字和0进行按位与操作都会得到0。因此,我们只需统计每一位上1的个数,在所有含有该位的子数组中,该位的贡献值即为 $2^{1的个数}-1$,其中 $-1$ 来自于长度为1的子数组的贡献没有计算。这种方法的时间复杂度为 $O(32N)$,其中 $N$ 是数组的长度。

def sum_of_all_subarrays(arr):
    result = 0
    for i in range(32):
        count = 0
        for num in arr:
            count += (num >> i) & 1
        result += count * (count - 1) * pow(2, i) // 2
    return result
总结

两种方法的时间复杂度分别为 $O(N^3)$ 和 $O(32N)$,显然后者更快。实际上,第二种方法可以看作是位运算的优化,可以应用到其他类似问题的解决中。