无意发现个代码,看大多博主都没说明原理,在这里解释一下:
找出n的二进制位为
1
的个数
int number_of_1(int n)
{
int count = 0;
while (n)
{
m = n & (n - 1);
count++;
}
return count;
}
原理:
(A、B为二进制,且B = A - 1)
A:10010011010100
B:10010011010011 = A-1
-
先看A、B的公共部分:(红色标注)
- A:1001001101010000
- B:1001001101001111
- A公共部分 & B公共部分 = A&B公共部分 -> 数字不变
-
现在我们主要分析的是,非公共部分:
- A:10010011010 10000
- B:10010011010 01111
现在假设:
- k : A中第一个二进制为
1
的位置 - 则 k 前面的二进制数必然全是
0
, - 那么B = A-1之后,从
1~k-1
的位置肯定都要借位,恰好到k的位置1
->0
高位 <- 低位 | 第k位:(第一个是1的位置) | 1~k-1位 | |
---|---|---|---|
A | 10010011010 | 1 | 0000 |
B | 10010011010 | 0 | 1111 |
A&B | 10010011010 | 0 | 0000 |
然后A = A&B
= 10010011010 00000
- 可以看到,经过A&B之后,发生的唯一变化是,第一个出现的
1
变成了0
- 或者通俗点讲:n&(n-1) 实现的效果就是把 第一个为
1
的二进制位转化为0
,其他部分不变
然后处理
A = 100100110 1000000
B = 100100110 0111111
可以看出:蓝色部分为刚刚二进制位为1
的数,
划分公共部分:
A= 1001001101000000
B= 1001001100111111
然后相同操作:
高位 <- 低位 | 第k位:(第一个是1的位置) | 1~k-1位 | |
---|---|---|---|
A | 10010011010 | 1 | 000000 |
B | 10010011010 | 0 | 111111 |
A&B | 10010011010 | 0 | 000000 |
然后,不断递归就行了