题目描述 :
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
方法1:手动转化法
直接想到的就是手动把数转化为二进制存进vector里,然后去数1的个数。当然这个很麻烦的地方在于负数是用补码,你把绝对值转化成二进制之后还得变成补码,工作量太多。
方法2:整数移位法
编程语言提供了位运算符,比如&(与)、|(或)、<<(左移)、>>(右移)等,位运算都是以二进制来操作的。
我们可以把这个整数不断右移,每右移一次就判定一次末尾是不是1,一直右移到这个数变成0。判定末尾的方法是和1作相与操作,与之后是1则说明原数这一位是1。
代码如下:
int count_one_way1(int num)
{
int counts=0;
while(num)
{
if((num&1)==1)
counts++;
num=num>>1;
}
return counts;
}
但是这段代码有问题,问题在于右移补位的时候,正数补0,而负数补1,所以如果num是个负数,会陷入死循环。
方法3:1移位法
为了避免上述问题,有一个改进方法是不移原来的数,我们把1这个数不断左移,和原数的每一位作相与,然后每次想与的结果不是0,就说明原数这一位是1。
代码如下:
int count_one_way2(int num)
{
int counts=0;
int t=1;
while(t!=0)
{
if((num&t)!=0)
counts++;
t=t<<1;
}
return counts;
}
这里会t会一直左移,本机int有多少位,t就会移动多少位,也就是会和num的每一位都比较到。
方法4:相邻数相与法
有一个很巧妙的方法是,n和n-1的相与结果,可以消掉n最右边的1。比如说11-00&1011=1000。所以我们只需要不断执行这种操作,就可以知道n有多少个1了。
代码如下:
int count_one_way3(int num)
{
int counts=0;
while(num)
{
counts++;
num=num&(num-1);
}
return counts;
}
方法5:函数法
c++有头文件提供了这个功能,这里尖括号里是32是因为我的电脑的int型是32位。
#include<bitset>
int count_one_way4(int num)
{
return bitset<32>(num).count();
}