《编程之美》--“1的数目”笔记

1的数目

给定一个是十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有“1”的个数。

例如:

N=2,写下1,2。这样只出现了1个“1”。

N=12,我们会写下1,2,3,4,5,6,7,8,9,10,11,12。这样,1的个数是5。


问题:写一个函数f(N),返回1到N之间出现的“1”的个数,比如f(12)=5;


解法:
仔细分析这个问题,给定了N,似乎就可以通过分析“小于N 的数在每一位上可能出现1的次数”之和来得到这个结果。对于一个特定的N,分析其中的规律。

先看1位数的情况
只要N>=1,那么f(N)都等于1。否则f(N)为0;

再看2 位数的情况。
如果N=13.那么从1到13的所有数字:1、2、3、4、5、6、7、8、9、10、11、12、13,个位和十位的数字都可能有1,我们可分开考虑。个位出现1的次数有两次:1和11,十位出现1的次数有4次:10、11、12和13,所以f(N)=2+4=6。要注意的是11这个数学在十位和个位都出现了1,但是11恰好分别被计算了一次,所以不用特殊处理。再考虑N= 23 的情况,它和N= 13 有点不同,十位出现1的次数为10次,从10到19,个位出现1的次数为1、11和21,所以f (N) =3+10= 13。通过对两位数进行分析,我们发现,个位数出现1的次数不仅和个位数字有关,还和十位数有关: 如果N的个位数大于等于I,则个位出现1的次数为十位数的数子加1; 如果N的个位数为0,则个位出现1的次数等于十位数的数字。而十位数上出现1的次数也类似: 如果十位数
字等于1,则十位数上出现1 的次数为个位数的数字加1; 如果十位数大于1,则十位数上出现1的次数为10。
f(13) =  一个位出现1的个数+ 十位出现1的个数=2+4=6:
f(23) =  一个位出现1的个数+ 十位出现1的个数=3+10=13;
f(33) = 一个位出现1的个数+ 十位出现1的个教=4+10 =14;
...
f(93) = 一个位出现1的个数+  十位出现1的个数=10+10= 20;

接着分析3 位数。
如果N= 123:
个位出现1的个数为13:1,11,21,...,91,101,111,121
十位出现1的个数为20:10~19,110~119
百位出现1的个数为24: 100~123
f(123)= 个位出现1的个数+十位出现1的个数十百位出现1的次数=13+20+24=57;
同理我们可以再分析4 位数、5位数。

根据上面的尝试,下面我们推导一般情况下,从N得到f(N) 的计算方法。
假设N=abcde,这a、b、c、d、e分别是十进制数N的各个数位上的数字。如果要t计算百位上出现1的次数,它将会受到三个因素的影响:百位上的数字,百位以下(低位) 的数字,百位(更高位) 以上的数字。
如果百位上的数字为0,可知,百位上可能出现1的次数由更高位决定,比如12013,百位出现1的情况可能是100~199,1100~2199,2100~2199,...,11100~11199,共有1200个。也就是由更高位数字(12)决定,并且等于更高位数字(12) x当前
位数(100)。

如果百位上的数字为1,可知,百位上可能出现1的次数不仅受更高位影响,还受低位影响。例如对于12 113,受更高位影响,百位出现1的情况是100~199,1100~1199,2100~2 199,...,11100~11199,一共1200 个,等于更高位数字( 12) x当前位数(100)。但是它还受低位影响,百位出现1的情况是12 100~ 12 113,一共114个,等于低位数字(113) +1。

如果百位上数字大于1(即为2~9),则百位上可能出现1的次数仅由更高位决定,比如12213,则百位出现1的可能性为: 100~199,1100~1199,2 100~2 199,...,1,100~1199,12 10~12199,一共有1300个,并且等于更高位数字加1,再乘以当前位数,即(12+ 1) X100。

以上为《编程之美》中的原文,以下便是自己写的



#include<stdio.h>
int main()
{
	int N,lower=0,higher=0,dang=0;//lower低位,higher高位,dang当前
	int wei=1,sum=0;
	scanf("%d",&N);
	while(N/wei)
	{
		lower=N-N/wei*wei;
		dang=N/wei%10;
		higher=N/(wei*10);
		switch(dang)
		{
			case 0:
				sum+=higher*wei;
				break;
			case 1:
				sum+=higher*wei+lower+1;
				break;
			default:
				sum+=(higher+1)*wei;
				break;
		}
		wei*=10;
	}
	printf("%d\n",sum);
	return 0;
} 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值