统计数字

统计数字问题。给定一本书,其中包含n页,计算出书的全部页码中用到了多少个数字0…9


样例输入:

  11

样例输出:

  1

  4

  1

  1

  1

  1

  1

  1

  1

  1


解法1:

暴力解决,统计0~9出现的次数,从1遍历到给出数字,对于每一个数字的每一位进行判断,在相应的数字数量上进行加1。


#include<stdio.h>
int main()
{
	int n;
	int i,count;
	int a[10]={0};
	while(scanf("%d",&n)){
		for(i=1;i<=n;i++){
			count=i;
			while(count){
				a[count%10]++;
				count=count/10;
			}
		} 	
		for(int i=0;i<10;i++)
			printf("%d\n",a[i]);
	}
	return 0;
}


解法2:

在数字递增过程中,认为进行位数补全,如1~99则变成00~99。而此时,每个数字出现的次数是相同的。

每个数字出现的次数为:f(n)=n*10^n-1(n为数字的位数);

因此利用上述公式进行求解。此时需要对给定数进行分解(例如2156)。

从第一位开始,分成三部分:

长度为4,所以能够选出000~999的两组,实际上是000~999和1000~1999根据公式可以求得此部分的数量;

最高位出现的次数,2出现的次数为2000~2156即为157次;

在最高位上出现但是小于最高位的数字出现的次数即0、1出现的次数,0为000~1000最高位上为0的次数为         pow(10,4-1),1为1000~1999同样是pow(10,4-1)。

在最高位分析完成之后,指针向后移动最高位变成1,长度为3按照上述步骤进行。

全部计算完成之后,需要减去多余的0,当数字为1时多余1个0,2位时多余1+10个0,3位时多余1+10+100个0;

#include<stdio.h>
#include<math.h>
#include<string.h>
int a[10];
int main()
{
	int n;
	while(~scanf("%d",&n)){
		memset(a,0,sizeof(a));
		int len = log10(n);
		int temp = n;
		int count;
		int high=0;
		int remain=0;
		for(int i=0;i<=len;i++)
		{
			high=temp/pow(10,len-i);//获取最高位 
			remain=temp-high*pow(10,len-i);//获取剩余位数的大小 
			a[high]+=remain+1;//最高位出现的次数因从0开始所以还需要加 1  
			for(int z=0;z<high;z++){
				a[z]+=pow(10,len-i); //小于最高位数字出现的次数,就是10的len-i次方。 
			}
			for(int j=0;j<10;j++){
				a[j]+=high*(len-i)*pow(10,len-i-1); 
				//类似00~99之间数字出现次数相同为(len)*(pow(10,len-1)) 
				//因为这里的实际长度为len-i;所以上式中len为len-i 
				//每个类似区间出现的次数为此时数字的最高位;					
			}
			temp=remain;
			//计算完成最高位之后,再次计算剩余部分,
			//此时把剩余数字当作初始数据计算。直到数字的长度为0 
		}
		for(int i=0;i<=len;i++){
			a[0]-=pow(10,i);
		}
		for(int j=0;j<10;j++){
			printf("%d\n",a[j]);
		}		
	}
	return 0;
}






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值