📌  相关文章
📜  将n表示为两个|的正好k次幂之和。套装2(1)

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

将n表示为两个|的正好k次幂之和 - 套装2

这个问题描述可以表示为:找到正整数 $a$ 和 $b$,使得 $n=2^a+2^b$,且 $a,b$ 均为正整数且互不相同。

解法1 - 暴力枚举

为了求出所有的满足条件的 $a$ 和 $b$,我们可以暴力枚举所有的 $a$ 和 $b$,时间复杂度为 $O(n^2)$,其中 $n$ 是数值的范围。

def findTwoPowers(n: int) -> List[Tuple[int, int]]:
    res = []
    for a in range(1, n):
        for b in range(a+1, n+1):
            if 2**a + 2**b == n:
                res.append((a,b))
    return res
解法2 - 二进制枚举

我们可以把 $n$ 转换成二进制数,假设其长度为 $l$,那么可能的 $a,b$ 的值只需在 $[1,l]$ 中枚举。如果用一个集合 $S$ 来存储所有 $2^x$,则只需要检查 $2^a$ 和 $2^b$ 是否同时在 $S$ 中即可。

def findTwoPowers(n: int) -> List[Tuple[int, int]]:
    S = set(2**i for i in range(n.bit_length()))
    res = []
    for a in range(1, n.bit_length()):
        if 2**a in S and (n - 2**a) in S and (n - 2**a) != 2**a:
            res.append((a, (n-2**a).bit_length()-1))
    return res

时间复杂度为 $O(n)$。

进一步优化

事实上,我们可以只枚举 $a$,然后通过二进制位运算计算出 $b$ 。具体做法是,令 $c = n - 2^a$,然后令 $b=lzc(c)$,其中 $lzc$ 表示从左边开始的连续 0 的个数。

def findTwoPowers(n: int) -> List[Tuple[int, int]]:
    S = set(2**i for i in range(n.bit_length()))
    res = []
    for a in range(1, n.bit_length()):
        if 2**a in S:
            c = n - 2**a
            b = c.bit_length()-c//2**lzc(c)-1
            if 2**b in S and a != b:
                res.append((a, b))
    return res

时间复杂度仍为 $O(n)$,但是常数因子比之前的做法更小。