1.
一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示而不是06或006。数字统计问题要求对给定书的总页码,计算出书的全部页码中分别用到多少次数字0,1,2,3,.....9。
思路:对于n位数,例如3位数,000-999,出现0,1,2...9的次数相同,记每个数字出现的次数为avg,这10个数字出现的总次数为sum=10*avg。
而n位数共有10^n个数,每个具体的数对于sum的贡献为n次。
得到:10*avg=n*10^n,
解出 avg=n*10^(n-1)。
2.
比如,对于一个数字34567,我们可以这样来计算从1到34567之间所有数字中每个数字出现的次数:
从0到9999,这个区间的每个数字的出现次数可以使用原著中给出的递推公式,即每个数字出现4000次。
从0到9999,这个区间的每个数字的出现次数可以使用原著中给出的递推公式,即每个数字出现4000次。
从10000到19999,中间除去万位的1不算,又是一个从0000到9999的排列,这样的话,从0到34567之间
的这样的区间共有3个。所以从00000到29999之间除万位外每个数字出现次数为3*4000次。然后再统计
万位数字,每个区间长度为10000,所以0,1,2在万位上各出现10000次。而3则出现4567+1=4568次。
之后,抛掉万位数字,对于4567,再使用上面的方法计算,一直计算到个位即可。
3.
1 // advance example 2 #include <iostream> // std::cout 3 #include <iterator> // std::advance 4 #include <list> // std::list 5 #include <cmath> 6 7 void statNumber(int n) { 8 int m, i, j, k, t, x, len = (int)log10(double(n));//*****调用函数求数字位数,机智 ***** 9 char d[16]; 10 int pow10[12] = {1}, count[10] = {0}; 11 // cout<<pow10[2]<<endl; 12 for(i = 1; i < 12; i++) { 13 pow10[i] = pow10[i-1] * 10; 14 } 15 sprintf(d, "%d", n);//example:n=9876, d[0]=9,d[1]=8,d[2]=7,d[3]=6,d[4..15]=[] 16 for( i=0;i<5;++i) 17 { 18 putchar(d[i]); 19 putchar(' '); 20 } 21 m = n+1;//!!! 22 for(i = 0; i <= len; i++) { 23 x = d[i] - '0'; 24 t = (m-1) / pow10[len-i]; 25 26 count[x] += m - t * pow10[len-i]; 27 28 t /= 10; 29 j = 0; 30 while(j <= x-1) { 31 count[j] += (t + 1) * pow10[len-i]; 32 j++; 33 } 34 while(j < 10) { 35 count[j] += t * pow10[len - i]; 36 j++; 37 } 38 count[0] -= pow10[len-i]; /* 第i个数位上前10^i个0是无意义的 */ 39 } 40 std::cout<<"number"<<" "<<"count"<<std::endl; 41 for(j = 0; j < 10; j++) { 42 std::cout<<j<<" "; 43 printf(" %d ", count[j]); 44 } 45 } 46 int main() 47 { 48 int a=1211; 49 std::cout<<"the number of pages is:"<<a<<std::endl; 50 51 statNumber(a); 52 system("PAUSE"); 53 return 1; 54 55 }
4.结果与分析
本算法循环次数=数字位数,对于问题规模N,循环次数m=log10(N),故而复杂性函数T=O(log10(N))。
5.发散与联想
推广1:___________
推广2:___________
::