如果您有足够的内存可玩,一种有效的方法可以对O(1)中数字的二进制表示形式中的1进行计数。这是我在在线论坛上发现的面试问题,但没有答案。有人可以提出建议吗,我想不出一种在O(1)时间内做到的方式?
如果您有足够的内存可玩,一种有效的方法可以对O(1)中数字的二进制表示形式中的1进行计数。这是我在在线论坛上发现的面试问题,但没有答案。有人可以提出建议吗,我想不出一种在O(1)时间内做到的方式?
Answers:
那就是汉明(Hamming)体重问题,也就是人口数。该链接提到了有效的实现。报价单:
有了无限的内存,我们可以简单地创建一个大的查找表,其中包含每个64位整数的汉明权重
我有一个解决方案,它可以计算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均为二进制),它将检查每一位。
编辑:刚刚找到了一个非常好的常量时间,常量存储算法用于位计数。它是用C编写的:
int BitCount(unsigned int u)
{
unsigned int uCount;
uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
您可以在这里找到其正确性的证明。
unsigned int
)。
请注意以下事实: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;
}
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);
}
if (orig & 1)
count++;
orig >>= 1;
更有效率吗?
count += orig & 1;
orig >>= 1;
那将是我一生中最短的答案:查找表。
显然,我需要解释一下:“如果您有足够的内存来玩”意味着我们已经拥有了所需的所有内存(无论技术可能性如何)。现在,您无需将查找表存储超过一两个字节。尽管从技术上讲它将是Ω(log(n))而不是O(1),但仅读取所需的数字就是Ω(log(n)),所以如果这是一个问题,那么答案是,不可能的,这是的。甚至更短。
他们在面试中期望您回答以下两个问题中的哪一个,没人知道。
还有另一个窍门:虽然工程师可以取一个数字并讨论Ω(log(n)),其中n是数字,但是计算机科学家会说,实际上,我们要根据输入长度的长度来衡量运行时间,因此工程师称Ω(log(n))实际上是Ω(k),其中k是字节数。但是,正如我之前所说,仅读取一个数字就是Ω(k),所以我们没有办法做得更好。
下面也将工作。
nofone(int x) {
a=0;
while(x!=0) {
x>>=1;
if(x & 1)
a++;
}
return a;
}
以下是使用位运算符的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;
}
我实际上是用一些技巧来完成此操作的:一个具有16个条目的查找表就足够了,而您要做的就是将二进制rep分成四位(4位元组)。实际上,复杂度是O(1),我写了一个C ++模板,专门针对您想要的整数大小(以#位为单位)…使之成为一个常量表达式,而不是不确定的。
可以使用以下事实:(i&-i)将为您返回LS一位,并简单地循环,每次都剥离lsbit,直到整数为零,但这是一个古老的奇偶技巧。
以下方法也可以计算负数中的1。
private static int countBits(int number) {
int result = 0;
while(number != 0) {
result += number & 1;
number = number >>> 1;
}
return result;
}
但是,像-1这样的数字在二进制中表示为11111111111111111111111111111111111,因此需要进行很多移位。如果您不想为较小的负数进行如此多的移位,则另一种方法可能如下:
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;
}
两种方式:
/* 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