思路:
1.右移原数字不可取,负数需要在左边添加1,会造成死循环。
则改成:首先把i和1做与运算,判断i的最低位是不是为1。接着把1左移一位得到2,再和i做与运算,就能判断i的次地位是不是1
循环的次数等于整数二进制的位数,32位的整数就需要循环32次。

  1. int NumberOf1(int n){
  2. int cnt = 0;
  3. unsigned int flag = 1;//必须是unsigned,不然只有31位
  4. while(flag)
  5. {
  6. if(n & flag == 1)
  7. cnt++;
  8. flag <<= 1;
  9. }
  10. return cnt;
  11. }

2.将一个数减1后,该数最右边的1将会变成0,而该位右边的0全变成1。将减1后得到的数和原数进行&运算,则包括该位在内的右边的数全都变成0(都不相同)。
有几个1就能进行几次以上的操作

  1. int NumberOf1(int n) {
  2. int cnt = 0;
  3. //比如1100,减1之后是1011,&运算后是1000,有多少个1,就可以执行多少次这样的运算;
  4. //必须是n!=0,n可能是负数阿
  5. while(n != 0){
  6. n = n & (n - 1);
  7. cnt++;
  8. }
  9. return cnt;
  10. }

引申题

1.用一条语句判断一个整数是不是2的整数次方:n & (n - 1) == 0
一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0

2.输入两个整数m和n,计算要改变m的二进制表示中的多少位才能得到n。
(1)m和n异或
(2)统计异或结果中1的位数

总结

把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0。很多二进制的问题都可以用这个思路解决。