输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
简单说明知识点:
1.原码、反码、补码
数字在计算机中是以特定的编码方式存储的,在这里以正数 +1 和负数 -1为例,以8位二进制存储。
原码:+1:0000 0001 -1:1000 0001 符号位加上真值的绝对值,第一位是符号位,0表示正数,1表示负数
反码:+1: 0000 0001 -1:1111 1110 正数的反码==原码,负数的反码==原码的符号位不变,其余位取反
补码:+1: 0000 0001 -1:1111 1111 正数的补码==原码,负数的补码==原码的符号位不变,其余位取反,再+1
+1 | -1 | |
原码 | 0000 0001 | 1000 0001 |
反码 | 0000 0001 | 1111 1110 |
补码 | 0000 0001 |
2.左移<< 和 右移 >>
有符号的左移 <<n, 扩大2^n倍
有符号的右移 >>n,缩小2^n倍, 例子 4>>2
4: 0000 0100 右移两位 0000 01
例子 -4>>2 ,最高位补1
-4: 1111 1100 右移两位 1111 1111
本题中注意输入的整数可能是正数 负数 零,负数在右移时,最高位补1。第一种思路可将整数转为无符号整数,再按照正数的处理方法即可。
第二种思路:先举个例子,一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
解1:
// solution 1:
int NumberOf1(int n)
{
if(n==0)
return 0;
unsigned int num=(unsigned int)n;
int count=0;
while(num!=0){
if(num&1==1)
count++;
num>>=1;
}
return count;
}
解2:
// solution 2:
int NumberOf1(int n)
{
if(n==0)
return 0;
int count=0;
while(n!=0){
count++;
n=n&(n-1);
}
return count;
}