题目
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
考察点
- 二进制与位运算
位运算:与(&
)、或(|
)、异或(^
)、左移(<<
)、右移(>>
).
左移(<<
)规则:
右边空出的位用0填补;高位左移溢出则舍弃该高位;计算机中常用补码表示数据。左移一位相当于乘以2.
右移(>>
)规则:
左边空出的位用0或者1填补;正数用0填补,负数用1填补。注:不同的环境填补方式可能不同;低位右移溢出则舍弃该位。 - 原码、反码与补码参考该博文
- 思维缜密与自查
解题思路
- 第一反应是:将n和1进行位与操作,遇见一个1,计数就加1,然后将n左移一位,将当下最右继续与1进行位与操作。缺点是:当遇到负数会产生死循环!原因:负数的存储是有符号位的(最左一位为1),当进行左移时,为了保证其为负数不变,最左依然是1,循环下去左边会被1填满!
- 改进:n动,移动1.
- 另一种思路:依靠对原码、反码以及补码的充分理解。如果一个整数不为0,那么这个整数至少有一位是1。如果把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1。其余所有位将不会受到影响。
完整代码
/*11_二进制中1的个数*/
#include<iostream>
using namespace std;
class Solution {
public:
int NumberOf1(int n)
{
int count = 0;
int flag = 1;
while (n != 0)
{
if ((n&flag) != 0)
count++;
flag = flag << 1;
}
return count;
}
int numberof1(int n)
{
int count = 0;
while (n != 0)
{
count++;
n = (n - 1)&n;
}
return count;
}
};
int main()
{
Solution s;
cout << s.NumberOf1(3) << endl;
cout << s.numberof1(12) << endl;
return 0;
}
注意
- 位操作是计算机中对数值的二进制形式操作。不用刻意将十进制转成二进制。