以二进制表示计数1的数量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了以二进制表示计数1的数量相关的知识,希望对你有一定的参考价值。
如果你有足够的内存可以用来计算O(1)中数字的二进制表示中1的数量的有效方法。这是我在网上论坛上发现的一个面试问题,但没有答案。有人可以提出一些建议,我想不出在O(1)时间内做到这一点的方法吗?
这就是Hamming weight问题,a.k.a。人口数量。该链接提到了有效的实现。引用:
通过无限的内存,我们可以简单地创建一个每64位整数的汉明权重的大型查找表
以下是使用位运算符的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;
}
以下是两个简单的例子(在C ++中),您可以通过它们执行此操作。
- 我们可以使用__builtin_popcount()简单地计算设置位(1)。
int numOfOnes(int x) { return __builtin_popcount(x); }
- 循环遍历整数中的所有位,检查是否设置了一个位,然后是否增加计数变量。
int hammingDistance(int x) { int count = 0 for(int i = 0; i < 32; i++) if(x & (1 << i)) count++; return count; }
希望这可以帮助!
javascript中最好的方法是
function getBinaryValue(num){
return num.toString(2);
}
function checkOnces(binaryValue){
return binaryValue.toString().replace(/0/g, "").length;
}
其中binaryValue是二进制字符串,例如:1100
我只能想到在O(1)中完成这项任务的一种方法......即“欺骗”并使用物理设备(使用线性甚至并行编程我认为限制为O(log(k))其中k表示数字的字节数)。
但是,您可以很容易地想象一个物理设备将每个位连接到具有0/1电压的输出线。然后你可以通过电子方式读取O(1)中'求和'线上的总电压。使用一些基本的电路元件使这个基本思想更加优雅,以任何你想要的形式产生输出(例如二进制编码输出),这很容易,但基本思想是相同的,电子电路会产生正确的输出在固定时间内的状态。
我想也有可能存在量子计算的可能性,但如果我们允许这样做,我认为简单的电子电路是更容易的解决方案。
实际上我已经使用了一些简单的手:一个包含16个条目的查找表就足够了,你所要做的就是将二进制代码分成半字节(4位元组)。复杂性实际上是O(1),我编写了一个C ++模板,专门用于你想要的整数大小(在#位中)...使它成为一个常量表达而不是不确定。
fwiw你可以使用这样一个事实,即(i&-i)将返回LS一位并简单地循环,每次都剥离lsbit,直到整数为零 - 但这是一个旧的奇偶校验技巧。
我来到这里时非常相信我知道这个问题的美妙解决方案。 C中的代码:
short numberOfOnes(unsigned int d) {
short count = 0;
for (; (d != 0); d &= (d - 1))
++count;
return count;
}
但是在我对这个主题进行了一些研究之后(阅读其他答案:))我发现了5种更有效的算法。爱你!
甚至还有专门为此任务设计的CPU指令:popcnt
。 (在this answer中提到)
许多算法的描述和基准测试,你可以找到here。
以下方法也可以以负数计算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;
}
在python或任何其他转换为bin字符串然后将其拆分为'0'以摆脱0然后组合并获得长度。
len(''.join(str(bin(122011)).split('0')))-1
通过利用JS的字符串操作,可以做如下操作;
0b1111011.toString(2).split(/0|(?=.)/).length // returns 6
要么
0b1111011.toString(2).replace("0","").length // returns 6
我不得不用红宝石打高尔夫球,然后结束了
l=->x{x.to_s(2).count ?1}
用法:
l[2**32-1] # returns 32
显然效率不高但诀窍:)
我有一个解决方案,计算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。
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)
两种方式::
/* 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
请注意以下事实: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)。
我从另一个网站看到了以下解决方案:
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;
}