以二进制表示计数1的数量

Tim*_*oad 70 algorithm binary

如果你有足够的内存可以用来计算O(1)中数字的二进制表示中1的数量的有效方法.这是我在网上论坛上发现的一个面试问题,但没有答案.有人可以提出一些建议,我想不出在O(1)时间内做到这一点的方法吗?

Ósc*_*pez 54

这就是汉明重量问题,即人口数量.该链接提到了有效的实现.引用:

通过无限的内存,我们可以简单地创建一个每64位整数的汉明权重的大型查找表

  • +1正确命名此问题.虽然我认为完整的答案会说即使使用查找表也不会是O(1)时间,因为查找任何条目的时间取决于条目的大小. (8认同)

060*_*002 43

我有一个解决方案,计算O(Number of 1's)时间位:

bitcount(n):
    count = 0
    while n > 0:
        count = count + 1
        n = n & (n-1)
    return count
Run Code Online (Sandbox Code Playgroud)

在最坏的情况下(当数字是2 ^ n - 1时,所有1都是二进制的)它将检查每一位.

编辑:刚刚为bitcount找到了一个非常好的恒定时间,常量内存算法.在这里,用C语言写成:

int BitCount(unsigned int u)
{
     unsigned int uCount;

     uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
     return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到它的正确性证明.

  • 你的第一个答案是O(log n)而不是O(1).你的第二个答案是O(1),但假设一个32位的域(输入参数是`unsigned int`). (4认同)
  • 如果可能,你能更新链接吗? (3认同)
  • 如果有人想知道 n = n & (n-1) 的作用,它会清除 n 的最低有效设置位 (1)。因此,当 n=0 时,我们在 while 内循环“回答”次数。 (2认同)

Sri*_*adi 17

请注意以下事实:n&(n-1)总是消除最不重要的1.

因此我们可以编写用于计算1的数量的代码,如下所示:

count=0;
while(n!=0){
  n = n&(n-1);
  count++;
}
cout<<"Number of 1's in n is: "<<count;
Run Code Online (Sandbox Code Playgroud)

程序的复杂性将是:n的1的数量(总是<32).


小智 15

我从另一个网站看到了以下解决方案:

int count_one(int x){
    x = (x & (0x55555555)) + ((x >> 1) & (0x55555555));
    x = (x & (0x33333333)) + ((x >> 2) & (0x33333333));
    x = (x & (0x0f0f0f0f)) + ((x >> 4) & (0x0f0f0f0f));
    x = (x & (0x00ff00ff)) + ((x >> 8) & (0x00ff00ff));
    x = (x & (0x0000ffff)) + ((x >> 16) & (0x0000ffff));
    return x;
}
Run Code Online (Sandbox Code Playgroud)


小智 10

public static void main(String[] args) {

    int a = 3;
    int orig = a;
    int count = 0;
    while(a>0)
    {
        a = a >> 1 << 1;
        if(orig-a==1)
            count++;
        orig = a >> 1;
        a = orig;
    }

    System.out.println("Number of 1s are: "+count);
}
Run Code Online (Sandbox Code Playgroud)

  • +1好答案.尝试添加一些解释.特别是对于两个方向上的位移部件,这可能会使一些人感到困惑. (4认同)
  • 嗨,我只是好奇,不会是`if(orig&1)``count ++;``orig >> = 1;`更高效一点? (3认同)
  • 解释:A)如果最低有效位为 1,则将计数器加 1(这是这部分的工作原理:右移,然后撤消移位将最低有效位设置为 0...如果旧数字和新数字之间的差为 1,则 a 1 被删除) B)将数字除以 2 并通过右移 1 C)重复直到数字为 0。将数字与 1 进行 AND 来确定最低有效数字是否为 1 会更容易。 (2认同)
  • 甚至更好:`count + = orig&1;`orig &gt;&gt; = 1;` (2认同)

小智 7

下面是两个简单的示例(C++ 语言),您可以通过它们来执行此操作。

  1. 我们可以使用 简单地计算设置位 (1) __builtin_popcount()
int numOfOnes(int x) {
  return __builtin_popcount(x);
}
Run Code Online (Sandbox Code Playgroud)
  1. 循环遍历整数中的所有位,检查是否设置了某个位,如果设置了则递增计数变量。
int hammingDistance(int x) {
  int count = 0;
  for(int i = 0; i < 32; i++)
    if(x & (1 << i))
      count++;
  return count;
}
Run Code Online (Sandbox Code Playgroud)


use*_*521 6

   countBits(x){
     y=0;
     while(x){   
       y += x &  1 ;
       x  = x >> 1 ;
     }
   }
Run Code Online (Sandbox Code Playgroud)

而已?