问题描述:一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示而不是06或006。
数字统计问题要求对给定书的总页码,计算出书的全部页码中分别用到多少次数字0,1,2,3,.....9。
对于这样一个数字统计,换而言之就是从1到num(num>1且num属于正整数)这个数列中出现0,1,2,3,.....9数字的次数分别是多少?
设f[n]为n位数中各个数字出现的次数,以2345为例,2345可以分为000-999,0至9出现的次数都为10f[n-1]+10n-1;1000-1999,0,2,3,4,5,6,7,8,9出现的次数都是10f[n-1]+10n-1,而1出现此时则为f[3]加上10的n-1次方即10的3次方,如f[3]为000~999中0~9中每一个数字出现的次数,则有,f[1]=1,f[n]=10f[n-1]+10n-1,故f[n]=n10n-1
可令long f[10]={0,1,20,300,4000,50000,600000,7000000,80000000,900000000};
以3512为例
(1)对千位上的数字a[1]=3进行处理:
S1:000~999,1000~1999,2000~2999中(不包括千位)包含的各数字的个数为count[j]+=3*f[3],f[3]为000~999中所含的各位数字的个数
S2:千位上的数字的个数:1、2各有103个
S3:3的个数为512+1个(从3000~3512)
(2)用同样的方法处理其余各位数5、1、2
(3)最后减去0的个数1111
//创建静态数组f表示各数字在n位数中出现的次数 static long [] f={0,1,20,300,4000,50000,600000,7000000,80000000,900000000}; //创建静态数组count用来存储各数字出现的次数 static long [] count={0,0,0,0,0,0,0,0,0,0};
public static void page(int a[]) {//用数组a来表示各位数的数字 int n = a.length; for(int i=1;i<=n;i++) {//从最高位开始计算到最低位 for (int j = 0; j < 10; j++) count[j] += a[i - 1] * f[n - i];//0到9的高位 for (int j = 0; j < a[i - 1]; j++) count[j] += Math.pow(10, n - i); for (int j = i+1; j <= n; j++) count[a[i-1]] += (a[j - 1] * Math.pow(10, n - j)); count[a[i-1]]++; } }
用数组a表示个位数的数字,从最高位开始计算0到9出现的次数至计算到最低位,
for (int j = 0; j < 10; j++) count[j] += a[i - 1] * f[n - i];即是000~999,1000~1999,2000~2999...的计算形式。
for (int j = 0; j < a[i - 1]; j++) count[j] += Math.pow(10, n - i);即是i-1数位上的数字n由1到n-1各出现Math.pow(10, n - i)的计算形式。
for (int j = i+1; j <= n; j++) count[a[i-1]] += (a[j - 1] * Math.pow(10, n - j));这里使用了递归说明比较复杂,用简明的说法就是以3512为例3的个数为512个(从3000~3512)而
count[a[i-1]]++;3的个数为512+1个,再从512返回for (int j = 0; j < 10; j++) count[j] += a[i - 1] * f[n - i];开始计算。
示例:
package jihe; import java.util.Scanner; /** * author Gsan */ public class Page { //创建静态数组f表示各数字在n位数中出现的次数 static long [] f={0,1,20,300,4000,50000,600000,7000000,80000000,900000000}; //创建静态数组count用来存储各数字出现的次数 static long [] count={0,0,0,0,0,0,0,0,0,0}; public static void page(int a[]) {//用数组a来表示各位数的数字 int n = a.length; for(int i=1;i<=n;i++) {//从最高位开始计算到最低位 for (int j = 0; j < 10; j++) count[j] += a[i - 1] * f[n - i];//0到9的高位 for (int j = 0; j < a[i - 1]; j++) count[j] += Math.pow(10, n - i); for (int j = i+1; j <= n; j++) count[a[i-1]] += (a[j - 1] * Math.pow(10, n - j)); count[a[i-1]]++; } } public static void main (String[]args){ int [] a={3,5,1,2}; page(a); for (int i = 0; i <a.length; i++) count[0] -= Math.pow(10, i); for (int i = 0; i < count.length; i++) System.out.println("数字" + i + "出现次数为:" + count[i]); } }
for (int i = 0; i <a.length; i++) count[0] -= Math.pow(10, i);减去如000-999这样形式与由1出现编码而多出来计算的0的次数的计算形式。
运行结果: