思路:

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;
    }
}