返回参数二进制中1的个数

目录

0).提出问题

来自牛客网的一道题目:写一个函数返回参数二进制中1的个数。
在这里插入图片描述

1).第一种思路

基本原理

在十进制位当中,想提取一个整数的每一位数字可以采取反复%10再/10的方法,直到得到0停止,如下图所示,123经过反复%10 /10 分离出1 2 3。那对于二进制来说,是否可以用类似的方法来分离每一位数字呢?

在这里插入图片描述

假设我们需要分离15的每一位数字,我们知道15在二进制中表示位00000000/00000000/00000000/00001111,这里我们将前面省略取后面八个数来表示15.

在这里插入图片描述

因为是二进制,所以我们需要%2/2来进行操作,我们可以发现每进行一次%2/2依然可以提取出每位数字,了解了基本原理,我们就可以做题啦!

解决方法:

题目给出了主函数部分,这里直接引用

int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = NumberOf1(n);//需要实现的函数
	printf("ret = %d", ret);
	return 0;
}

此时我们用以下代码实现while循环和if语句来计算1的数量。

int NumberOf1(int n)
{
	int count = 0;//初始化计数器
	while (n)//当n不等于0时进入循环
	{
		if (n % 2 == 1)
		{
			count++;//当%2后得出1即分离出的数字为1计数器加1
		}
		n = n / 2;
	}
	return count;
}

15的二进制位为00001111,结果为4代码正确,然而输入负数后代码就会运行错误,该如何优化代码?
在这里插入图片描述

优化代码

在这里插入图片描述
****-1的原码是10000000/00000000/00000000/00000001,按位取反得到反码后为11111111/11111111/11111111/11111110,反码加一得到补码为11111111/11111111/11111111/11111111,理应得到ret=32,程序是哪里出问题了呢?


当n=-1时,进入循环后%2余-1,-1/2为0,循环结束,count为0
解决方法:unsigned 修饰 int n,这是-1会被认为是一个超级大的整数,没有符号概念,得出正确答案32

int NumberOf1(unsigned int n)
{
	int count = 0;//初始化计数器
	while (n)//当n不等于0时进入循环
	{
		if (n % 2 == 1)
		{
			count++;//当%2后得出1即分离出的数字为1计数器加1
		}
		n = n / 2;
	}
	return count;
}

在这里插入图片描述

2).第二种思路

基本原理

在二进制位中,想分离出某位数字,只要给这位数字按位与1即可,如果一个数按位与1结果位1,那么这个数的最低位一定为1,如果想往前计算数字,可以用位运算符解决,二进制中有32位数字,则循环32次

解决方法

int NumberOf1(int n)
{
	int count = 0;//初始化计数器
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (((n >> i) & 1) == 1)//右位移运算符循环32次使每一位数字都按位与1,得到1则计数器+1
		{
			count++;
		}
	}
	return count;
}

得出正确答案,实现代码
在这里插入图片描述
在这里插入图片描述

3).第三种思路

基本原理

一个巧妙的方法,我们让n&(n-1),假设n=15请添加图片描述

解决方法

int NumberOf1(int n)
{
	int count = 0;//初始化计数器
	int i = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}

得到正确答案
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值