问题陈述是:
编写一个有效的程序,以整数的二进制表示形式计算1的数量。
我发现了一个关于此问题here的帖子,其中概述了在log(n)时间内运行的多个解决方案,包括Brian Kernigan的算法和gcc __builtin_popcount()
方法。
没有提到的一个解决方案是python方法:bin(n).count("1")
这也达到了同样的效果。此方法是否也在log n时间运行?
答案 0 :(得分:6)
您正在将整数转换为字符串,这意味着它必须生成N #include<stdio.h>
int main(){
int n1,n2,n3,n4,n5;
printf("Please enter the cost of the car then your down payment\n");
scanf("%d%d",&n1,&n2);
n3=n1-n2;
printf("Now enter how many months of financing you would like\n");
scanf("%d",&n4);
n5=n3*1.05/n4;
printf("Your car payment is %d per month",n5);
return 0;
}
和'0'
个字符。然后使用必须访问字符串中每个字符的'1'
来计算str.count()
个字符。
总而言之,你有一个O(N)算法,其成本相对较高。
请注意,这与您链接的代码具有相同的复杂性;整数'1'
具有log(n)位,但算法仍需要进行N = log(n)步骤来计算位数。因此n
算法是等效的,但慢,因为首先产生字符串的成本很高。
以表为代价,您可以转移到每个字节处理整数 :
bin(n).count('1')
但是,由于Python需要生成一系列新对象(一个table = [0]
while len(table) < 256:
table += [t + 1 for t in table]
length = sum(map(table.__getitem__, n.to_bytes(n.bit_length() // 8 + 1, 'little')))
对象和几个整数),因此这种方法的速度不足以超越bytes
方法:
bin(n).count('1')
无论测试号码的位长度如何,>>> from random import choice
>>> import timeit
>>> table = [0]
>>> while len(table) < 256:
... table += [t + 1 for t in table]
...
>>> def perbyte(n): return sum(map(table.__getitem__, n.to_bytes(n.bit_length() // 8 + 1, 'little')))
...
>>> def strcount(n): return bin(n).count('1')
...
>>> n = int(''.join([choice('01') for _ in range(2 ** 16)]))
>>> for f in (strcount, perbyte):
... print(f.__name__, timeit.timeit('f(n)', 'from __main__ import f, n', number=1000))
...
strcount 1.11822146497434
perbyte 1.4401431040023454
总是慢一个百分点。
答案 1 :(得分:4)
假设您正在尝试计算n
的设置位数。在 Python 典型实现中,bin
将在O(log n)
时间内计算二进制表示,count
将遍历字符串,从而导致整体{{1}复杂性。
但是,请注意,通常,算法的输入参数是输入的“大小”。使用整数时,这对应于它们的对数。这就是为什么当前算法具有线性复杂度(变量为O(log n)
,复杂度为m = log n
)。