在王晓东编著的《算法设计与实验题解》中看到的这个问题,问题描述如下:
一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示而不是06或006。数字统计问题要求对给定书的总页码,计算出书的全部页码中分别用到多少次数字0,1,2,3,.....9。
这个题目有个最容易想到的n*log10(n)的算法。这是自己写的复杂度为O(n*log10(n))的代码:
- void statNumber(int n) {
- int i, t;
- int count[10] = {0};
- for(i = 1; i <= n; i++) {
- t = i;
- while(t) {
- count[t%10]++;
- t/=10;
- }
- }
- for(i = 0; i < 10; i++) {
- printf("%d/n", count[i]);
- }
- }
仔细考虑m个n位十进制数的特点,在一个n位十进制数的由低到高的第i个数位上,总是连续出现10^i个0,然后是10^i个1……一直到10^i个9,9之后又是连续的10^i个0,这样循环出现。找到这个规律,就可以在常数时间内算出第i个数位上每个数字出现的次数。而在第i个数位上,最前面的10^i个0是前导0,应该把它们减掉。
这样,可以只分析给定的输入整数n的每个数位,从面可以得到一个log10(n)的算法,代码如下:
- void statNumber(int n) {
- int m, i, j, k, t, x, len = log10(n);
- char d[16];