思路:
1.利用一个结论:一个二进制数n减1后与原二进制数进行&运算( 即n&(n-1) )会消去最右边的1。
2.这个结论怎么来的?
- 假设二进制数101进行减1运算,刚好最右边是1,则得到100,此时用100跟101做&运算,得到的是100,故消去了101左右边的1。
- 100减1呢?最低位是0,跟十进制减法一样啊,向高位借。(可以脑补一下十进制100减1的过程)
所以二进制100减1的运算过程如下:
- 最右边的0向右数第二位借1得:2-1=1,
- 右数第二位还是0,却要借给最右边那位1,所以它也得向高位借。
- 这样右数第三位的1借给它1之后变成0,右数第二位借1得:2-1=1。
- 所以得到新数为011。
观察一下刚刚的运算过程可以发现:
- 如果最右边刚好是1(如101),进行减1运算就不用向高位借,直接得0,高位则保持原样不变(得100)。
- 再把减1后得到的数与原数&运算(即101&100=100)可知高位都不变那就是消去最右边的1!(由这可能还不太明显是消去最右边的1,继续看下面的)
- 如果最右边是0(如100),进行减1运算,则需要像高位借,而最终会导致最近的高位1因为被借走1而变0,而比它高的高位保持原样不变(得011),再跟原来的数进行&运算(即100&011=000);
- 所以由以上两点可知二进制数每次减1后与原数进行&运算会消去最右边的1。
答案:
因为n&(n-1)每次都消去最右边的1,最终1全被消去会得到0,所以有几个1就可以进行几次n&(n-1)。
public class Solution { public int NumberOf1(int n) { int count = 0; while(n!=0){ count++; n=n&(n-1); } return count; } }