此问题来自2011年代码打印(http://csfall11.interviewstreet.com/):
计算机科学的基础之一是知道数字如何以2的补码表示。想象一下,使用32位写下A和B之间的所有数字,包括2的补码表示。你会写下多少1? 输入: 第一行包含测试用例数T(<1000)。每个下一个T行包含两个整数A和B. 输出: 输出T线,一个对应于每个测试用例。 约束: -2 ^ 31&lt; = A&lt; = B&lt; = 2 ^ 31-1
示例输入: 3 -2 0 -3 4 -1 4 样本输出: 63 99 37
说明: 对于第一种情况,-2包含31 1后跟0,-1包含32 1和0包含0 1。因此,总数是63。 对于第二种情况,答案是31 + 31 + 32 + 0 + 1 + 1 + 2 + 1 = 99
我意识到你可以使用-X中的1的数量等于(-X)= X-1的补码中的0的数量以加速搜索的事实。该解决方案声称有一个O(log X)递归关系用于生成答案但我不明白。解决方案代码可在此处查看:https://gist.github.com/1285119
如果有人能解释这种关系是如何产生的,我将不胜感激!
答案 0 :(得分:31)
嗯, 复杂......
单参数solve(int a)
函数是关键。它很短,所以我将它剪切并粘贴在这里:
long long solve(int a)
{
if(a == 0) return 0 ;
if(a % 2 == 0) return solve(a - 1) + __builtin_popcount(a) ;
return ((long long)a + 1) / 2 + 2 * solve(a / 2) ;
}
它仅适用于非负a,它计算从0到a
的所有整数中的1位数。
该功能有三种情况:
a == 0
- &gt;返回0.显然。
a
偶数 - &gt;返回a
加solve(a-1)
中的1位数。也很明显。
最后一个案例是有趣的。那么,我们如何计算从0到奇数{1}的1位数?
考虑0和a
之间的所有整数,并将它们分成两组:平均值和赔率。例如,如果a
为5,则您有两个组(二进制):
a
和
000 (aka. 0)
010 (aka. 2)
100 (aka. 4)
观察这两个组必须具有相同的大小(因为001 (aka 1)
011 (aka 3)
101 (aka 5)
是奇数且范围是包含的)。要计算每组中有多少1位,首先计算除最后位之外的所有位,然后计算最后位。
除最后一位之外的所有位都是这样的:
a
... 两个组看起来都是这样。这里的1位数仅为00
01
10
。 (在这个例子中,它是从0到2的1位数。另外,回想一下C / C ++中的整数除法将向下。)
对于第一组中的每个数字,最后一位为零,对于第二组中的每个数字,最后一位为0,因此最后一位对总数贡献solve(a/2)
一位。
因此递归的第三种情况为(a+1)/2
,并对(a+1)/2 + 2*solve(a/2)
进行了适当的强制转换,以处理long long
为a
的情况(从而INT_MAX
溢出)。
这是一个O(log N)解决方案。要将其概括为a+1
,您只需计算solve(a,b)
,再加上适当的逻辑来担心负数。这就是两个参数solve(b) - solve(a)
正在做的事情。
答案 1 :(得分:3)
将数组转换为一系列整数。然后对每个整数执行:
int NumberOfSetBits(int i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
这也是便携式的,与__builtin_popcount
不同见这里:How to count the number of set bits in a 32-bit integer?
答案 2 :(得分:2)
当a为肯定时,已经发布了更好的解释。
如果a是负数,那么在32位系统中,a和0之间的每个负数将使32个1位减去从0到正数a的二进制表示的位数。
所以,以更好的方式,
long long solve(int a) {
if (a >= 0){
if (a == 0) return 0;
else if ((a %2) == 0) return solve(a - 1) + noOfSetBits(a);
else return (2 * solve( a / 2)) + ((long long)a + 1) / 2;
}else {
a++;
return ((long long)(-a) + 1) * 32 - solve(-a);
}
}
答案 3 :(得分:1)
在下面的代码中,x的位数被定义为0和x(包括)之间的数字的二进制补码表示中的1位计数,其中Integer.MIN_VALUE&lt; = x&lt; = Integer.MAX_VALUE。
例如:
bitsum(0) is 0
bitsum(1) is 1
bitsum(2) is 1
bitsum(3) is 4
...等
10987654321098765432109876543210 i % 10 for 0 <= i <= 31
00000000000000000000000000000000 0
00000000000000000000000000000001 1
00000000000000000000000000000010 2
00000000000000000000000000000011 3
00000000000000000000000000000100 4
00000000000000000000000000000101 ...
00000000000000000000000000000110
00000000000000000000000000000111 (2^i)-1
00000000000000000000000000001000 2^i
00000000000000000000000000001001 (2^i)+1
00000000000000000000000000001010 ...
00000000000000000000000000001011 x, 011 = x & (2^i)-1 = 3
00000000000000000000000000001100
00000000000000000000000000001101
00000000000000000000000000001110
00000000000000000000000000001111
00000000000000000000000000010000
00000000000000000000000000010001
00000000000000000000000000010010 18
...
01111111111111111111111111111111 Integer.MAX_VALUE
bitsum的公式是:
bitsum(x) = bitsum((2^i)-1) + 1 + x - 2^i + bitsum(x & (2^i)-1 )
注意x - 2 ^ i = x&amp; (2 ^ I)-1
负数的处理方式与正数略有不同。在这种情况下,从总位数中减去零的数量:
Integer.MIN_VALUE <= x < -1
Total number of bits: 32 * -x.
负数x中的零个数等于-x - 1中的个数。
public class TwosComplement {
//t[i] is the bitsum of (2^i)-1 for i in 0 to 31.
private static long[] t = new long[32];
static {
t[0] = 0;
t[1] = 1;
int p = 2;
for (int i = 2; i < 32; i++) {
t[i] = 2*t[i-1] + p;
p = p << 1;
}
}
//count the bits between x and y inclusive
public static long bitsum(int x, int y) {
if (y > x && x > 0) {
return bitsum(y) - bitsum(x-1);
}
else if (y >= 0 && x == 0) {
return bitsum(y);
}
else if (y == x) {
return Integer.bitCount(y);
}
else if (x < 0 && y == 0) {
return bitsum(x);
} else if (x < 0 && x < y && y < 0 ) {
return bitsum(x) - bitsum(y+1);
} else if (x < 0 && x < y && 0 < y) {
return bitsum(x) + bitsum(y);
}
throw new RuntimeException(x + " " + y);
}
//count the bits between 0 and x
public static long bitsum(int x) {
if (x == 0) return 0;
if (x < 0) {
if (x == -1) {
return 32;
} else {
long y = -(long)x;
return 32 * y - bitsum((int)(y - 1));
}
} else {
int n = x;
int sum = 0; //x & (2^i)-1
int j = 0;
int i = 1; //i = 2^j
int lsb = n & 1; //least significant bit
n = n >>> 1;
while (n != 0) {
sum += lsb * i;
lsb = n & 1;
n = n >>> 1;
i = i << 1;
j++;
}
long tot = t[j] + 1 + sum + bitsum(sum);
return tot;
}
}
}