从1到N的二进制形式正数中1出现的次数

例如:f(11) = f(1011) = 20(1,10,11,100,101,110,111,1000,1001,1010,1011)

思路:先考虑第一位上的1(第几位一律从右侧数起),第一位上的1是每两个数出现1次,因此可以先计算11/2=5,然后对于11%2=1的部分,由于等于1,因此出现了一次1,故第一位上共出现了6次1;再考虑第二位,这一位上是每4个数出现2次1,先计算11/4*2=4,对于11%4=3的部分,只有在10-11之间会出现2次1,因此第二位上出现了6次1;第三位,(11/8*4)+0=4,第四位,0+(11-7)=4。因此f(1011)=10100=20。

总结一下:设index是二进制的位数(从0开始,依次递加),factor是2的整数次方(从2开始,依次递乘2),

                   factor = 2*(index+1)

                   index上出现1的次数为n/factor + 0(如果n%factor < factor/2)或者n%factor-factor/2+1(如果n%factor >= factor/2)

 

#include <stdio.h>

int NumsOf1(int n)
{

	int count = 0;
	int factor = 2;
	int a, b, c;
	int index = 0;

	do
	{
		a = n/factor;
		b = n%factor;
		c = a*(factor/2);

		count += c;
		if(b >= factor/2)
		{
			count += b-factor/2+1;
		}
		factor *= 2;
		index++;
	}while(a != 0);

	return count;
}

int main()
{
	int n;
	printf("输入n的值:\n");
	scanf("%d",&n);
	int count = NumsOf1(n);
	printf("从1到%d的二进制正数中1出现的次数%d\n",n,count);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值