面试题14:二进制中1 的个数
1 题目
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
2 思路
1.由于负数右移会在最左边补1,因此不能右移,否则可能陷入死循环
2.首先判断n和1做与运算判断n的最低位是不是为1.接着把1左移一位得2,再和n做与运算,就能判断n的磁低位是不是1……,反复左移,每次都能判断n的其中一位是不是1.
3.如果一个整数与1做与运算结果是1,表示该整数最右边一位是1,否则是0.
3 代码
int NumberOf1(int n)
{
int cnt = 0;
unsigned int flag = 1;
while(flag){
if(n & flag)cnt++; //不管n是不是负数,都成立
cout<<flag<< " after ";
flag=flag<<1;
cout<<flag<<endl;
}
return cnt;
}
4 优化
上述解法,循环次数等于整数的二进制位数,32位需要循环32次。
我们可以把一个整数减去1,
- 一个不为0的整数,那么它的二进制表示中至少有一个1,
- 我们可以假设最后一位不是1而是0的情况,若最右边的1位于第m位,减去1之后,该位变成0,它之后的每一位都取反为1,
- 若最后一位为1,则直接取反。
4.把一个整数减去1后再和原整数做与运算,会把该整数最右边的1变成0,因此1的个数会减少一位,每与一次减少一个1,直到输入的数为0.
int NumberOf2(int n)
{
int cnt = 0;
unsigned int flag = 1;
while(n){
cnt++;
n=n&(n-1);
}
return cnt;
}
5 拓展
输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n?
比如 10 的二进制为1010,13的二进制为1101,需要改变3位才能得到1101.可以分为两步:1,求解这两个数的异或,第二步统计异或结果中1的位数。

浙公网安备 33010602011771号