📅  最后修改于: 2023-12-03 15:39:14.189000             🧑  作者: Mango
这个问题描述可以表示为:找到正整数 $a$ 和 $b$,使得 $n=2^a+2^b$,且 $a,b$ 均为正整数且互不相同。
为了求出所有的满足条件的 $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
我们可以把 $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)$,但是常数因子比之前的做法更小。