题目描述
输入一个整数(10进制),输出该数二进制表示中1的个数。其中负数用补码表示。
题目思路
思路1:将10进制转化为2进制,那么我们是否可以将2进制数以"10进制"的方法表示呢?比如十进制的5表示为2进制的101,我们把101当成十进制,然后每次除以10判断该位是否为1,但是这有存在两个问题,如果数据过大是存在越界问题,另外如果是负数我们是存在符号位的,这会导致越界以及难以判断,所以该思路可能可行,但代码难以实现。
思路2:我们是否可以将二进制存储到一个数组当中呢,比如这题输入的是一个int型整数,在32位编译器上我们可以知道这是转化为32位二进制的,其中包含一个符号位。当整数为正时,我们清楚该数的源码、反码、补码都是一致的,并且符号位为0;当整数为负时,该数的源码和其整数一致,反码取反,补码在反码基础上+1。那么我们按照这个思路,可以设计代码。最后检测该数组中有多少个1即可,代码详见下图,附有备注思路。
思路3:该思路来自和别人的讨论。因为我们知道,在计算机中本身存储就是以0,1方式存储的,那么正数是以源码形式存储的,负数是以补码形式存储的。那么我们可以想到用1以及&符号与每一位进行判断,若为真则为1,反之为假。
代码
思路2代码:
class Solution {
public:
int NumberOf1(int n) {
if(n<0)
return false;
if(n==0)
return 0;
bool symbol=true; //标记n是否为负数,负数为false
bool isJin=true; //标记a[0]即二进制末尾是否为1,为1为true
int a[33]={0};
if(n<0)
{
symbol=false;
n=-n;
a[31]=1; //a[31]为符号位
}
int count=0,i=0;
while(n!=0) //转化为二进制,并存在数组a中,末位存前面
{
a[i++]=n%2;
n=n/2;
}
if(!symbol) //如果为负数需进行取反+1操作
{
i=32;
for(int j=0;j<31;j++) //取反,符号位不变
{
if(a[j]==0)
a[j]=1;
else if(a[j]==1)
a[j]=0;
}
if (a[0] == 1) //判断二进制最后一位是否为1,+1是否进位
isJin = false;
if (isJin)
{
a[0] = 1;
}
if(!isJin)
{
for (int j = 1; j < 31; j++) //+1
{
if (a[j] == 0)
break;
a[j]=0;
}
a[0] = 1;
}
}
for(int j=0;j<i;j++) //查找多少位为1
if(a[j]==1)
count++;
return count;
}
};
思路3代码:
class Solution {
public:
int NumberOf1(int n) {
int count=0;
int flag=1;
while(flag)
{
if(n&flag)
count++;
flag=flag<<1; //每次flag要往左移一位
}
return count;
}
};