📜  总和为 2 的幂的对数 | 2套(1)

📅  最后修改于: 2023-12-03 14:54:20.418000             🧑  作者: Mango

总和为 2 的幂的对数 | 2套

简介

本题要求计算在给定数组中,和为 2 的幂的对数。其中数组中的元素均为整数。

输入格式

一个数组 \lstinline{arr},其长度为 \lstinline{n},其中每个元素均为整数。

输出格式

返回数组 \lstinline{arr} 中和为 2 的幂的对数。

示例

输入:

arr = [1,2,3,4,5,6,7,8,9]

输出:

6
解法

题目要求的是和为 2 的幂的对数,我们可以将问题转化为:

对于每个元素,求其与其他元素的和是否为 2 的幂,然后统计答案。

具体实现时,我们可以首先枚举两个元素的下标,计算它们的和是否为 2 的幂。如果是,将结果计入答案。时间复杂度为 $O(n^2)$。

代码片段如下:

def countPairs(arr: List[int]) -> int:
    n = len(arr)
    res = 0
    for i in range(n):
        for j in range(i+1, n):
            s = arr[i] + arr[j]
            if s & (s - 1) == 0:
                res += 1
    return res

上述算法的时间复杂度为 $O(n^2)$,空间复杂度为 $O(1)$。对于规模较大的输入,可能会超时,因此需要优化算法。

观察上述算法,我们发现计算 $2^{n}$ 或 $2^{n}-1$ 的值可能会浪费大量时间,因为这些值并不是我们需要的结果。

因此,我们考虑优化计算过程。具体而言,在计算每个数的二进制表示时,我们只需要知道它的最高位和最低位分别是什么,因为这两个数之和才可能是 2 的幂。具体实现时,我们遍历数组,对于每个元素,计算其二进制表示下的最高位 $h$ 和最低位 $l$。接着,我们枚举每个 $2^k$,其中 $0\le k < h$,计算 $2^k-l$ 是否在数组中出现,如果是,则将答案加上该值出现的次数。时间复杂度为 $O(n\log{V})$,其中 $V$ 表示所有数的最大值。

代码片段如下:

def countPairs(arr: List[int]) -> int:
    n = len(arr)
    res = 0
    for i in range(n):
        h = 0
        l = arr[i]
        while l > 0:
            h += 1
            l >>= 1
        mask = (1 << h) - 1
        for k in range(h):
            x = (1 << k) - l
            if x > arr[i] and x & mask == x:
                res += 1
    return res

上述算法的时间复杂度为 $O(n\log{V})$,空间复杂度为 $O(1)$。与暴力算法相比,时间复杂度得到了显著的降低。