题目:给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数。
要求:写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数。例如 f(12) = 5。在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少。
一、设计思路
首先,此题可以用从1到N遍历一遍的方法来解决。即输入一个数除以10取余数,如果余数等于1则计数加1,否则计数加0,然后此数除以10,直到此数除以10结果等于0。然而,此种方法多做了很多无用功。我们做练习的目的并不是实现程序,而是学会各种算法来优化程序。所以,此题第二种解法则是统计各种情况下,“1”个数的变化规律。
规律变化:
f(3)=1;
f(13)=2+1;f(23)=3+10;f(33)=4+10;f(43)=5+10;f(53)=6+10;f(63)=7+10;……;f(93)=10+10;
f(103)=11+10+4;f(113)=12+12+14;f(123)=13+20+24;……
……
通过对数字进行有规律的总结,发现从1到N,中出现的所有的1的总数。可以从N这个数总结出来的。
f(N)=个位上出现1的次数+十位上出现1的次数+百位上出现1的次数+……
所以对于一个数abcde,取百位上的c来计算,
假若c是"1",那么百位上1的个数是由他的高位和低位来决定的。等于ab*100+cde+1;
假若c是"0",那么百位上1的个数是ab*100;
假如c是大于1,那么 百位上1的个数是(ab+1)*100;
二、源代码
1 #include <iostream.h> 2 int f(int n) 3 { 4 int Count=0; 5 int Factor=1; 6 int LowerNum=0; 7 int CurrNum=0; 8 int HigherNum=0; 9 while(n/Factor!=0) 10 { 11 LowerNum=n-(n/Factor)*Factor; 12 CurrNum=(n/Factor)%10; 13 HigherNum=n/(Factor*10); 14 switch(CurrNum) 15 { 16 case 0: 17 Count+=HigherNum*Factor; 18 break; 19 case 1: 20 Count+=HigherNum*Factor+LowerNum+1; 21 break; 22 default: 23 Count+=(HigherNum+1)*Factor; 24 break; 25 } 26 Factor*=10; 27 } 28 return Count; 29 } 30 int main() 31 { 32 int num; 33 cout<<"请输入十进制整数:"<<endl; 34 cin>>num; 35 cout<<f(num)<<endl; 36 return 0; 37 }
三、运行结果
四、个人总结
由于定义的全是int类型,所以输入的数据不宜过大。通过找规律而优化程序,减少了程序的运行次数,能使程序更加迅速地运行。遍历一遍的方法太过简单,使用此方法,对于我们来说,并未获得什么有价值的经验。而使用此种方法,却过于考验我们的脑力,让我对程序的用途产生了思考,程序到底是为了方便还是为了节约运行时间?但是,如果只是为了方便,凡是有点编程基础的都能解决此类问题,我们的存在就失去了意义。我们的工作就是优化用户与计算机之间的交流通道。