有人可以解释为什么Brian Kernighan的算法需要O(log N)来计算整数中的设置位(1s)。该算法的简单实现如下(在JAVA中)
int count_set_bits(int n){
int count = 0;
while(n != 0){
n &= (n-1);
count++;
}
return count;
}
我理解它是如何工作的,一个接一个地清除最右边的设置位,直到它变为0,但我只是不知道我们如何得到O(log N)。
答案 0 :(得分:23)
该算法经历与设置位一样多的迭代。因此,如果我们有一个只有高位设置的32位字,那么它只会循环一次。在最坏的情况下,它每位传递一次。整数n
具有log(n)
位,因此最坏的情况是O(log(n))
。这是你的代码注释的重要位(双关语):
int count_set_bits(int n){
int count = 0; // count accumulates the total bits set
while(n != 0){
n &= (n-1); // clear the least significant bit set
count++;
}
}
答案 1 :(得分:6)
N中存在floor(lg(N))+ 1个有效位 - 这是基数2的对数。 n中的1位数最多为此。所以时间渐近上限为O(lg(N))= O(log(N))。
答案 2 :(得分:4)
这个问题实际上是关于大O符号中N的含义,而不是算法的复杂性。
N表示数据的大小。但是,如果“数据”是单个数字,您需要定义您理解的数据大小。它的表示的数量或长度的值。
IMO算法是O(N)。因为在这个以二进制表示IMO计数1的问题中,相关的数据大小是数字表示的长度,而不是它的值,即比特流的长度。显而易见的最坏情况是1次采用N次迭代。
但是如果你将N的值视为数据的大小,它的表示具有log(N)长度,所以你可以说它是O(log(N))
PS只有当你为任意高的Ns推广算法时,大O符号才有意义。在这段代码中,N受int大小的限制,所以你可以说它是O(1),因为它最多将是64次循环迭代(对于64位整数)