我有一个函数接收一个整数并返回一个由2的幂组成的集合,其总和等于输入值:
def bin_set(n):
b = set()
while n:
hbit = 1 << n.bit_length()-1
b.add(hbit)
n -= hbit
return b
所以我计算数字的最高位并将其添加到集合中,但是我应该将n
的值发送到循环的下一次迭代?我使用了n = n-hbit
因为while
的条件而且它在某种程度上有效,但我很确定这是一种错误的做法。
是否有不同的方法可以做到这一点,可能是使用不同的循环而没有对数/ bit twiddling / bit_length()或者这是唯一的方法吗?
答案 0 :(得分:1)
这种方法很好用;您是通过减法从n
中删除检测到的位,直到删除所有位。结果,n.bit_length()
结果也会减少。
您可以使用XOR(^
运算符)来清除高位,而不是减法:
def bin_set(n):
b = set()
while n:
hbit = 1 << n.bit_length() - 1
b.add(hbit)
n ^= hbit
return b
另一种方法是右移高位而不是改变n
:
def bin_set(n):
b = set()
hbit = 1 << n.bit_length() - 1
while hbit:
if n & hbit: # the high bit is set
b.add(hbit)
hbit >>= 1
return b
但这实际上做了更多测试!
您的版本只循环次数与n
中设置的位数相同,但每次迭代计算位数,而上述版本循环n.bit_length()
次。 int.bit_length()
需要O(N)平均时间来计算位长度,因此你需要O(KN)时间来从N位产生K值集合,将高位移位需要O(N)时间。
这使得我的版本渐近变得更好,但是因为int.bit_length()
方法在C中工作并且将循环减少到每4位只有一次循环迭代,所以它并没有听起来那么糟糕。在你开始看到我的胜利之前,你需要 humongous 号码。
答案 1 :(得分:0)
你可以使用一种名为set comprehension的东西,这是一种非常简洁的方法来创建它们。
def bin_set(n):
return {1 << p for p in xrange(n.bit_length()-1, -1, -1) if n & 1 << p}
print bin_set(0) # --> set([])
print bin_set(10) # --> set([8, 2])
print bin_set(12) # --> set([8, 4])
print bin_set(15) # --> set([8, 1, 2, 4])