数字统计——把握数字规律

  问题描述:

一本书的页码从自然数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 }

这个算法和上面穷举的算法的效率就是天和地的区别。

由于先前粗略翻过《编程之美——微软技术面试心得》,看到这道题并没有多想什么,很直接地就想到了用这个算法。数字的规律很微妙,组合更加不用说,现在做的算法的题目大多数都与组合思想有关。

 

 

转载于:https://www.cnblogs.com/zhuorongtan/archive/2012/09/19/2678172.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值