统计数字问题

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

分析与解答:

由0,1,2……9组成的所有的n位数,从n个0到n个9共有10^n个n位数,其中全排列的情况下,每个数字使用的次数一样,设为f(n).

0 0 0 0 ...... 0

0 0 0 0 ...... 1

.............

9 9 9 9 ...... 9

 

公式可以这么理解:n位数字 数i的总次数为f(n) =  

                  n-1位数字的数i的总次数f(n-1)与第一位为0-9 组合   = 10f(n-1)

                   +

                 第一位数字为数i,其他n-1位为0-9组合全排列的数i的次数  =10n-1

 

我们其实可以知道:f(n)=n10n-1

据此,可以从高向低位进行统计,再减去多余的0的个数即可。

 

void Statistical(int n) {

      //声明一个数组记录从0到9出现的次数

            int[] count = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

          int len = (int)Math.Log10(n);  //计算去掉最高位的位数

            int tempLen = len;

      //位数为len的全排列的情况 每个数字出现次数

            int mode = (int)Math.Pow(10, tempLen);                    

      int h = n / mode;                //获取最高位数值

            n %= mode;

            while (tempLen > 0) //直到当位数为2位以上

            {            
        //计算去掉最高位数字段,每个数字使用的次数一样为f(n) n为去掉最高位后位数 根据全排列的情况下 for (int i = 0; i < 10; i++) { count[i] += h * tempLen * mode / 10; }         //计算最高位为0~h-1时, 0~h-1 数字出现的次数为去掉最高位 全排列次数 for (int i = 0; i < h; i++) count[i] += mode;         //计算最高位位h时出现次数为:去掉最高位的数字 + 1(加1是因为从0开始) count[h] += n + 1; mode = (int)Math.Pow(10, --tempLen); h = n / mode; n %= mode; } //计算当位数为1时的次数 for (int i = 0; i <= h; i++) count[i] += 1; //去掉前导0的个数 tempLen = len; for (int i = 0; i < len; i++) { mode = (int)Math.Pow(10, tempLen--); count[0] -= mode; } }
原文地址:https://www.cnblogs.com/gyb333/p/Statistics_problem.html