题目:
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网
![](https://img-blog.csdnimg.cn/img_convert/a2111c2a58b7e5fabf028e3deefb2611.png)
![](https://img-blog.csdnimg.cn/img_convert/83019fcabdd8b50893e073efce89e13c.png)
![](https://img-blog.csdnimg.cn/img_convert/8d92cc282ce43f358c3ba13ab54b4cb7.png)
思考一:
我们在计算十进制数字每一位时经常采用这种方法:
int main()
{
int a = 123;
while (a)
{
printf("%d ", a % 10); //取余操作,相当于取出最后一位
a = a / 10; //除法,相当于去掉最后一位
}
}
![](https://img-blog.csdnimg.cn/img_convert/4937fb7c0b91e38765339a81d9e656bd.png)
同理,在解决二进制问题时,将10换成2即可。
int NumberOf1(int n)
{
int count = 0; //统计1的个数
while (n)
{
if (n % 2 == 1) //取出二进制补码的最后一位,并且判断是否为1
count++;
n = n / 2; //去掉二进制补码中的最后一位
}
return count;
}
但是有一个问题,当n为负数时,会出错,解决方法也很简单
int NumberOf1(unsigned int n) //将数据类型换成无符号整型,这样补码的符号位也会参与计算
{
int count = 0; //统计1的个数
while (n)
{
if (n % 2 == 1)
count++;
n = n / 2;
}
return count;
}
以上方法确实能够解决问题,但该方法却无法直接提交到网站上
![](https://img-blog.csdnimg.cn/img_convert/c1ce24277e6723df16c7df0a570a9a90.png)
题目要求不允许修改参数类型,那么本题只能舍弃思路一。
思路二:
按位与操作符的特点是两个数按位与,其对应的二进制位有0,则为0,两个同时为1,才为1
int NumberOf1(int n)
{
int i = 0;
int count = 0;
for (i = 0; i < 32; i++)
{
if (((n >> i) & 1) == 1) //右移0~31位,逐位判断是否是1(注意右移操作不改变n本身的值)
{
count++;
}
}
return count;
}
这样就解出了该题。
改进:
此处留下改进后更完善(高级)的方法,不与讲解,供感兴趣的诸位参考。
int NumberOf1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}