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

时间:2012-01-15 16:18:45

标签: algorithm binary

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

21 个答案:

答案 0 :(得分:53)

这是Hamming weight问题,a.k.a。人口数量。该链接提到了有效的实现。引用:

  

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

答案 1 :(得分:41)

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

bitcount(n):
    count = 0
    while n > 0:
        count = count + 1
        n = n & (n-1)
    return count

在最坏的情况下(当数字是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;
}

您可以找到其正确性的证据here

答案 2 :(得分: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;

程序的复杂程度为:n的1的数量(常数<32)。

答案 3 :(得分:14)

我在其他网站上看到了以下解决方案:

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;
}

答案 4 :(得分: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);
}

答案 5 :(得分:6)

   countBits(x){
     y=0;
     while(x){   
       y += x &  1 ;
       x  = x >> 1 ;
     }
   }
那是吗?

答案 6 :(得分:3)

这将是我生命中最短的答案: 查询表。

显然,我需要解释一下:“如果你有足够的内存可以玩”意味着,我们已经拥有了我们需要的所有内存(绝不是技术可能性)。现在,您不需要将查找表存储超过一个或两个字节。虽然它在技术上是Ω(log(n))而不是O(1),但只需读取你需要的数字是Ω(log(n)),所以如果这是一个问题,那么答案是 < em>不可能 - 甚至更短。

他们在接受采访时期待你的两个答案中的哪一个,没有人知道。

还有另一个技巧:虽然工程师可以拿一个数字并谈论Ω(log(n)),其中n是数字,计算机科学家会说实际上我们要测量运行时间作为<的函数输入的em> length ,工程师称之为Ω(log(n))实际上是Ω(k),其中k是字节数。不过,正如我之前所说,只读数字是Ω(k),所以我们无法做得更好。

答案 7 :(得分:2)

下面也可以。

nofone(int x) {
  a=0;
  while(x!=0) {
    x>>=1;
    if(x & 1)
      a++;
  }
  return a;
} 

答案 8 :(得分:1)

javascript中最好的方法是

function getBinaryValue(num){
 return num.toString(2);
}

function checkOnces(binaryValue){
    return binaryValue.toString().replace(/0/g, "").length;
}

其中binaryValue是二进制字符串,例如:1100

答案 9 :(得分:1)

以下是两个简单的例子(在C ++中),您可以通过这些示例执行此操作。

  1. 我们可以使用__builtin_popcount()简单地计算设置位(1&#39; s)。

    int numOfOnes(int x) { return __builtin_popcount(x); }

  2. 循环遍历整数中的所有位,检查是否设置了一个位,然后是否增加计数变量。

    int hammingDistance(int x) { int count = 0 for(int i = 0; i < 32; i++) if(x & (1 << i)) count++; return count; }

  3. 希望这有帮助!

答案 10 :(得分:1)

以下是使用位运算符的C解决方案:

int numberOfOneBitsInInteger(int input) {
  int numOneBits = 0;

  int currNum = input;
  while (currNum != 0) {
    if ((currNum & 1) == 1) {
      numOneBits++;
    }
    currNum = currNum >> 1;
  }
  return numOneBits;
}

以下是使用2的幂的Java解决方案:

public static int numOnesInBinary(int n) {

  if (n < 0) return -1;

  int j = 0;
  while ( n > Math.pow(2, j)) j++;

  int result = 0;
  for (int i=j; i >=0; i--){
    if (n >= Math.pow(2, i)) {
        n = (int) (n - Math.pow(2,i));
        result++;    
    }
  }

  return result;
}

答案 11 :(得分:1)

该函数采用int并以二进制表示形式返回Ones的数量

public static int findOnes(int number)
{

   if(number < 2)
    {
        if(number == 1)
        {
            count ++;
        }
        else
        {
            return 0;
        }
    }

    value = number % 2;

    if(number != 1 && value == 1)
        count ++;

    number /= 2;

    findOnes(number);

    return count;
}

答案 12 :(得分:0)

我来到这里时非常相信我知道这个问题的美妙解决方案。 C代码:

    short numberOfOnes(unsigned int d) {
        short count = 0;

        for (; (d != 0); d &= (d - 1))
            ++count;

        return count;
    }

但是在我对这个主题进行了一些研究之后(阅读其他答案:))我发现了5种更有效的算法。爱你!

甚至还有专门为此任务设计的CPU指令:popcnt。 (在this answer中提到)

您可以找到许多算法的说明和基准测试here

答案 13 :(得分:0)

在python或任何其他转换为bin字符串然后将其拆分为'0'以除去0然后合并并获得长度。

len(''.join(str(bin(122011)).split('0')))-1

答案 14 :(得分:0)

以下方法也可以以负数计算1的数量。

private static int countBits(int number)    {
    int result = 0;
    while(number != 0)  {
        result += number & 1;
        number = number >>> 1;
    }
    return result;
}

然而,像-1这样的数字用二进制表示为1111111111111111111111111111111111,因此需要大量移位。如果你不想为小的负数做这么多的转变,另一种方法可能如下:

private static int countBits(int number)    {
    boolean negFlag = false;
    if(number < 0)  { 
        negFlag = true;
        number = ~number;
    }

    int result = 0;
    while(number != 0)  {
        result += number & 1;
        number = number >> 1;
    }
    return negFlag? (32-result): result;
}

答案 15 :(得分:0)

通过利用JS的字符串操作,可以执行以下操作;

0b1111011.toString(2).split(/0|(?=.)/).length // returns 6

0b1111011.toString(2).replace("0","").length  // returns 6

答案 16 :(得分:0)

我实际上已经使用了一些简单的手:一个包含16个条目的查找表就足够了,你所要做的就是将二进制代表分成半字节(4位元组)。复杂性实际上是O(1),我编写了一个C ++模板,它专门用于你想要的整数大小(在#位中)......使它成为一个常量表达而不是不确定。

fwiw你可以使用这样一个事实,即(i&amp; -i)将返回LS一位并简单地循环,每次都剥离lsbit,直到整数为零 - 但这是一个旧的奇偶校验技巧。 / p>

答案 17 :(得分:0)

我不得不用红宝石打高尔夫球,然后结束

l=->x{x.to_s(2).count ?1}

用法:

l[2**32-1] # returns 32

显然效率不高但是诀窍:)

答案 18 :(得分:0)

Ruby实现

def find_consecutive_1(n)
  num = n.to_s(2)
  arr = num.split("")
  counter = 0
  max = 0
  arr.each do |x|
      if x.to_i==1
          counter +=1
      else
          max = counter if counter > max
          counter = 0 
      end
      max = counter if counter > max  
  end
  max
end

puts find_consecutive_1(439)

答案 19 :(得分:0)

两种方式::

/* Method-1 */
int count1s(long num)
{
    int tempCount = 0;

    while(num)
    {
        tempCount += (num & 1); //inc, based on right most bit checked
        num = num >> 1;         //right shift bit by 1
    }

    return tempCount;
}

/* Method-2 */
int count1s_(int num)
{
    int tempCount = 0;

    std::string strNum = std::bitset< 16 >( num ).to_string(); // string conversion
    cout << "strNum=" << strNum << endl;
    for(int i=0; i<strNum.size(); i++)
    {
        if('1' == strNum[i])
        {
            tempCount++;
        }
    }

    return tempCount;
}

/* Method-3 (algorithmically - boost string split could be used) */
1) split the binary string over '1'.
2) count = vector (containing splits) size - 1

<强>使用::

    int count = 0;

    count = count1s(0b00110011);
    cout << "count(0b00110011) = " << count << endl; //4

    count = count1s(0b01110110);
    cout << "count(0b01110110) = " << count << endl;  //5

    count = count1s(0b00000000);
    cout << "count(0b00000000) = " << count << endl;  //0

    count = count1s(0b11111111);
    cout << "count(0b11111111) = " << count << endl;  //8

    count = count1s_(0b1100);
    cout << "count(0b1100) = " << count << endl;  //2

    count = count1s_(0b11111111);
    cout << "count(0b11111111) = " << count << endl;  //8

    count = count1s_(0b0);
    cout << "count(0b0) = " << count << endl;  //0

    count = count1s_(0b1);
    cout << "count(0b1) = " << count << endl;  //1

答案 20 :(得分:0)

只有一种方法可以让我想到在O(1)中完成这个任务......就是'欺骗'并使用物理设备(使用线性甚至并行编程我认为限制是O(log(log) k))其中k表示数字的字节数。

然而,您可以很容易地想象一个物理设备将每个位连接到具有0/1电压的输出线。然后你可以通过电子方式读取O(1)中'求和'线上的总电压。使用一些基本的电路元件使这个基本思想更加优雅,以任何你想要的形式产生输出(例如二进制编码输出),这很容易,但基本思想是相同的,电子电路会产生正确的输出固定时间的状态。

我想也有可能存在量子计算的可能性,但如果我们允许这样做,我认为简单的电子电路是更容易的解决方案。