统计数字问题

统计数字问题

问题描述:
一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6 页用数字6 表示,而不是06 或006 等。数
字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。

编程任务:

给定表示书的总页码的10 进制整数n (1≤n≤109) 。编程计算书的全部页码中分别用到多少次数字0,1,2,…,9。

数据输入:

输入数据由文件名为input.txt的文本文件提供。每个文件只有1 行,给出表示书的总页码的整数n。

结果输出:

程序运行结束时,将计算结果输出到文件output.txt中。输出文件共有10行,在第k行
输出页码中用到数字k-1 的次数,k=1,2,…,10。
输入文件示例 输出文件示例
input.txt 
11

output.txt
1
4
1
1
1
1
1
1
1
1


解题思路

这个题目不难,主要考察递归思想(当然也可以用其他形式代替递归),但这个题目也有一定的技巧性,思维灵活性要求较高。

最初,我看到这个题目的时候觉得很esay,不就是排列组合的问题嘛。把公式列出来O(1)的复杂度就可以解决,但当构思写伪代码的时候,发现被难住了,因为n不是确定的一个数,并且0-n的数据不等长,所以很难写出有效的排列组合公式。这里使用另一种方法来解决此问题。

由于不同位数的数字不等长,导致编程实现遇到非常不方便,我们采取迂回的路线,正面不行,则从侧面入手。首先,我们先让0-n的每一位数字的高位补上若干位0,数字大小不变,但长度和n的位数保持一致,这里我成为数字对齐。例如,n=423,则每一个数字补0后变成,000,001,..,010,..,422,423。

数字对齐后,进行分组,分成000-399,400-423这两个组,000-399可以用排列组合的方式很容易计算出出现多少个0(此时0的出现次数,多于最终要求的次数,因为有多余的前导0),1,2,..,9。然后在400-423这个组中,最高位4共出现24次,这个时候就需要统计的便是00-23中出现多少个0,1,..,9了,此时只要递归调用程序来处理23就行了(即原来n=423,一次递归之后,n=23)。


下面给出源代码

int a[10];
int exp(int n)
{
int sum=1;
for(int i=1;i<=n;i++)
sum*=10;
return sum;
}


void number_count(const int n)
{
if(n<=0)
return;
/**求出n的位数以及n的最高位数字*/
int high=0;
int num=0;
int tmp=n;
while(tmp>0)
{
sum++;
tmp/=10;
if(tmp/10==0)
high=tmp;
}

/*根据排列组合计算00..0-(hihg-1)99..9中出现的0-9的个数*/
int t1=exp(num-1);
int t2=exp(num-2);
for(int i=0;i<=9;i++)
{
if(i<high)
a[i]=t1+t2;
else a[i]=t2;
}
a[high]+=n-high*t1+1;

/*递归*/
number_count(n-high*t1);

/*去掉多计算的0*/
for(int i=1;i<num;i++)
{
a[0]-=(num-i)*exp(i);
}

}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值