二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 —— [ 牛客网 ]
本题要求求解整数二进制数据中1的个数,看到题目的时候,第一想法应该是遍历一遍二进制数,计算总数。即每一次与1之后右移,判断是1则加1。
class Solution {
public:
int NumberOf1(int n){
int count = 0;
while(n){
if(n & 1)count ++;
n = n >> 1;
}
return count;
}
};
针对正整数而言,这样的算法可以解决问题,但是针对负整数而言,题目说采用的补码形式存储,最高位是1代表负数,例如16位的整形负数-8,补码形式为:1111111111111000。
1111111111111000-->1111111111111100 右移一位
1111111111111100-->1111111111111110 右移一位
1111111111111110-->1111111111111111 右移一位
...
对于负数的右移操作,为保证右移后依然是负数,所以填充的是1,如果按照上面的算法思路,当填充到全1的时候,算法会陷入死循环。
为了避免死循环,我们采用相对位移的方式,既然不能右移整数,那我们左移与运算的1的位置,计算1的个数。
解法一
class Solution {
public:
int NumberOf1(int n){
int count = 0;
unsigned int flag = 1;
while(flag){
if(n & flag)count ++;
flag = flag << 1;
}
return count;
}
};
假设我们计算机的整形数据表示是32位的,那么计算一次我们需要计算32次,如果能够直接确定1的位置这样来计算,可以更加快速的得到结果。
例如我们有整数110101,我们将整数减1可得到整数中最末尾的一个1的位置之后的所有为0的数字转换为1,而1之前的数字不变,进一步n&(n-1),即计算了一次1的位置。
110101 - 1 = 110100 110101 & 110100 = 110100 第一个1出现
110100 - 1 = 110011 110100 & 110011 = 110000 第二个1出现
110000 - 1 = 101111 110000 & 101111 = 100000 第三个1出现
100000 - 1 = 011111 100000 & 011111 = 000000 第四个1出现,找到全部的1
解法二
class Solution {
public:
int NumberOf1(int n){
int count = 0;
while(n){
count ++;
n = n & (n-1);
}
return count;
}
};
巧妙的转换思维,利用二进制位运算的技巧。