【剑指Offer-位运算】面试题15:二进制中1的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路1

可以先判断该整数对应的二进制最右一位是不是1,判断方法为将整数的二进制和1做与运算(&),如果整数二进制的最右一位是1,则与运算结果为1,否则为0。将整数二进制最右一位进行判断后右移一位(>>),直至整数为0。但这种方法只能判断非负整数二进制中1的个数,因为负数二进制的第一位为1,当进行右移操作时,左边会补上1,最终造成死循环。

思路2

在思路1中是右移整数二进制&1进行判断,但这种方法会造成死循环。为了避免死循环,我们保持输入整数的二进制不变,对1左移(<<)后和整数二进制与操作进行判断,这样每次都能判断整数二进制中的一位,在这个算法中,循环的次数等于整数1的二进制位数,例如32位的整数需要循环32次。代码如下:

class Solution {
public:
     int  NumberOf1(int n) {
         unsigned int flag=1;    //要使用unsigned int
         int cnt=0;
         while(flag){
             if(flag&n)
                 cnt++;
             flag = flag<<1;
         }
         return cnt;
     }
};

需要注意的是,1的类型要是unsigned int,不能是int。

思路3

思路2可以准确统计整数二进制中1的个数,但总要循环32次。在思路3中,整数二进制中包含多少个1,就循环多少次。首先有一个技巧:把一个整数减去1后,再和原来的整数做与运算,得到的结果就相当于把原来整数二进制最靠右一位的1转为0。例如,整数二进制可以分为两种情况,最靠右一位的1就是最右一位(如1011)和最靠右一位的1不是最后一位(如1010)。最靠右一位的1就是最右一位,假设为1101,则1011-1=1100,1011&1100=1010,1011最右一位变成了1;当最靠右一位的1不是最后一位,假设为1010,此时1010-1=1001,1010&1001=1000,最靠右一位的1(从左往右第3位)变成了1。这样,整数二进制中有多少位1,就可以进行多少次上面的操作(因为每次都把最靠右一位的1变成0,直到所有的1都变成0,那么整数值也为0,即为循环终止条件)。代码如下:

class Solution {
public:
     int  NumberOf1(int n) {
         int cnt=0;
         while(n){
             n = (n-1)&n;
             cnt++;
         }
         return cnt;
     }
};

总结

把一个整数减去1后,再和原来的整数做与运算,得到的结果就相当于把原来整数二进制最靠右一位的1转为0。

posted @ 2020-03-07 21:41  Flix  阅读(184)  评论(0编辑  收藏  举报