问题描述:
一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示,而不是06或006。数字统计问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,3,…,9。
编程任务:
给定表示书的总页码的十进制整数n(1<<n<<109)。编程计算书的全部页码中分别用到多少次数字0,1,2,3,…,9。
数据输入:
输入数据由文件名input.txt的文本文件提供。每个文件只有1行,给出表示书的总页码的整数n。
结果输出:
程序运行结束时,将计算结果输出到文件output.txt中。输出文件共有10行,在第k行输出页码中用到数字k-1的次数,k=1,2,3,…,10。
第一眼看到这道题目,心里暗喜太简单了。一开始我想直接用穷举就可以把这道题算出来,但是这样做的效率实在令人汗颜。
我也不妨把穷举的代码列出来:
1 #include<iostream> 2 using namespace std; 3 4 int main() 5 { 6 int count[10]={0}; 7 int num, j, temp; 8 cin>>num; 9 10 for(int i=num; i>0; i--) 11 { 12 temp=i; 13 while(temp) 14 { 15 count[temp%10]++; 16 temp=temp/10; 17 } 18 } 19 for(int l=0; l<10; l++) 20 cout<<count[l]<<endl; 21 22 return 0; 23 }
能解决问题的代码并不一定是好代码。就像对于这种算法,很显然其花费的时间就是n*logn,效率低得不像样了吧。对于此,不能再用“不管白猫还是黑猫,抓到老鼠就是好猫”的评判标准啦。
对于数字这些问题,通常都会存在内在的规律,可以方便直接地算出所想要的结果。
首先来看看《编程之美——微软技术面试心得》一书中的一道题目“1的数目”。
如果看懂了这道《1的数目》,再来看这道题,就是小儿科了吧。
依照《编程之美——微软技术面试心得》的算法,应该是在其基础上改动一下,就可以得到了这道题完美的答案。详细请看下面代码:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 const int N=10; 6 string str;//输入数n 7 int a[N]; 8 void NumCount(int n); 9 10 int main() 11 { 12 a[0]=1; 13 for(int i=1; i<N; i++) 14 a[i]=a[i-1]*10; 15 while(cin>>str) 16 { 17 int n=0; 18 int len=str.size(); 19 for(int i=0; i<len; i++) 20 { 21 n=n*10+(str[i]-'0'); 22 } 23 //cout<<n<<endl; 24 NumCount(n); 25 } 26 return 0; 27 } 28 29 void NumCount(int n) 30 { 31 int count[N]={0}; 32 int iFactor=1; 33 int iLowerNum=0; 34 int iCurrNum=0; 35 int iHigherNum=0; 36 37 while(n/iFactor!=0) 38 { 39 iLowerNum=n-(n/iFactor)*iFactor; 40 iCurrNum=(n/iFactor)%10; 41 iHigherNum=n/(iFactor*10); 42 43 for(int i=0; i<N; i++) 44 { 45 if(iCurrNum<i) 46 count[i]+=iHigherNum*iFactor; 47 else if (iCurrNum==i) 48 count[i]+=iHigherNum*iFactor+iLowerNum+1; 49 else 50 count[i]+=(iHigherNum+1)*iFactor; 51 } 52 iFactor*=10; 53 } 54 55 int len=str.size(); 56 for(int k=0; k<len; k++) 57 { 58 count[0]-=a[len-k-1]; 59 } 60 //cout<<count[0]-exzero<<endl; 61 62 for(int j=0; j<N; j++) 63 cout<<count[j]<<endl; 64 }
这个算法和上面穷举的算法的效率就是天和地的区别。
由于先前粗略翻过《编程之美——微软技术面试心得》,看到这道题并没有多想什么,很直接地就想到了用这个算法。数字的规律很微妙,组合更加不用说,现在做的算法的题目大多数都与组合思想有关。