问题描述:
一本书的页码从自然数1开始计数,直到自然数n。书的页码按照通常的习惯编排,每个页码都不包含多余的前导数字0。例如,第6页用数字6表示,而不是06或006等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,...,9。
参考代码:
方法一
暴力求解。无论页码是多少都是从1...n,所以我们可以从1到n进行遍历并对每个数进行分解即可得到结果
#include<stdio.h>
int main(){
int n,i,temp;
//声明并且初始化数组
int count[10]={0};
printf("请输入页码:");
scanf("%d",&n);
//从1到n遍历数字,并分解将对应数字加1
for(i=1;i<=n;i++){
for(temp=i;temp>0;temp/=10){
count[temp%10]++;
}
}
//遍历输出
for(i=0;i<10;i++)
printf("%d\n",count[i]);
return 1;
}
方法二
考虑一个数字12345,在个数上,数字出现的频率是1次,即0到9不断循环出现;而在10位数字上(如果十位上没有数字就补0,要求从0到12345这些数字的位数都和最大的数相同,这里就都是5位),每个数字是连续出现10次后再出现另一个数字;百位数字上依此类推……
基于这个思路,如果我们能计算出0到9这10个数字在每一位上出现的次数,对它们进行求和,即可计算出这10个数字出现的次数。
考虑**X**,在第3位上统计相关数字出现的次数。一般地,数字出现的次数与X的大小有直接的有关系。
(1)如果数字比X大,则它在这一位上出现的次数与前面的数字和该数字所在的位置有关。例如,12345中,数字4在第3位出现的次数为:
12*100=1200
(2)如果数字等于X,则它在这一位上出现的次数与前面的数字、后面的数字和该数字所在的位置有关。例如,12345中,数字3在第3位上出现的次数为:
12*100+45+1=1246
(3)如果数字小于X,则它在这一位上出现的次数与前面的数字和该数字所在的位置有关。例如,12345中,数字2在百位上出现的次数为
(12+1)*100=1300
#include<stdio.h>
#include<math.h>
int main(){
int n,i,j,highter,lower,temp;
int ws;
//声明并且初始化数组
int count[10]={0};
printf("请输入页码:");
scanf("%d",&n);
//计算n的位数
ws=log10((double)n)+1;
//依次计算第i(i小于ws)位0到9出现的次数
for(i=1;i<=ws;i++){
//记录第i位之上的高位
highter=n/(int)pow((double)10,i);
//记录第i位之下的低位
lower=n%(int)pow((double)10,i-1);
//记录第i位
temp=(n/(int)pow((double)10,i-1))%10;
//记录小于第i位的数字在i位出现的次数
for(j=0;j<temp;j++){
count[j]+=(highter+1)*pow((double)10,i-1);
}
//记录第i位上的数字在第i位出现的次数
count[temp]+=highter*pow((double)10,i-1)+lower+1;
//记录大于第i位的数字在第i位出现的次数
for(j=temp+1;j<10;j++){
count[j]+=highter*pow((double)10,i-1);
}
}
//剔除多余的0
for(i=0;i<ws;i++)
count[0]-=(int)pow((double)10,i);
//遍历输出
for(i=0;i<10;i++)
printf("%d\n",count[i]);
return 1;
}
方法三
给定一个n位数字number,我们首先看一下从0到最大的n位数字,如果位数不够,在前面填0,这样一共有10^n个数字,其中包含数字的个数是n*10^n,其中包含这10个数字是相同的,都为n*10^{n-1}位。
能否根据这一思路,从高位到低位依次处理?得到最终的位数?可以首先把最高位的数字单独处理,然后再处理其他的n-1位,最后把那些多余的0全部去掉就可以了。
#include<stdio.h>
#include<math.h>
int main(){
int n,i,j,k,highter,lower,temp;
int ws;
//声明并且初始化数组
int count[10]={0};
printf("请输入页码:");
scanf("%d",&n);
//计算n的位数-1
ws=log10((double)n);
//将n分解,依次记录最高位数字
temp=n;
for(i=0;i<=ws;i++){
//取得最高位数字
highter=temp/pow((double)10,ws-i);
//取得低位数字
lower=temp%(int)pow((double)10,ws-i);
//记录最高位数字在最高位出现的次数
count[highter]+=lower+1;
//依次记录从0到最高位数字highter的数字在最高位出现的次数以及从0到ws-i位最大数0到9出现的次数
for(j=0;j<highter;j++){
count[j]+=pow((double)10,ws-i);
//0到ws-i位最大数0到9出现的次数
for(k=0;k<10;k++){
count[k]+=(ws-i)*pow((double)10,ws-i-1);
}
}
temp=lower;
}
//剔除多余的0
for(i=0;i<=ws;i++)
count[0]-=(int)pow((double)10,i);
//遍历输出
for(i=0;i<10;i++)
printf("%d-->%d\n\n1",i,count[i]);
return 1;
}