一、题目与要求
- 给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数。
- 要求:写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数。例如 f(12) = 5。
在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少。
二、设计思路
寻找1的出现的个数,可以采用枚举的方式,统计1出现的个数,但是,这种算法效率不高,那么,在正整数中,1出现的个数是有规律的,如果能找到这个规律,效率应该会得到很大的提高。举例:
个位 | 十位 | 百位 | 。。。 | |
3 | 1 | 0 | 0 | 。。。 |
13 | 2 | 4 | 0 | 。。。 |
23 | 3 | 10 | 0 | 。。。 |
33 | 4 | 10 | 0 | 。。。 |
。。。 | 。。。 | 。。。 | 。。。 | 。。。 |
93 | 10 | 10 | 0(0*100) | 。。。 |
103 | 11 | 10(1*10) | 4((3+1)+(0*100)) | 。。。 |
113 | 12 | 14(1*10+4) | 14((13+1)+(0*100)) | 。。。 |
123 | 12 | 20((1+1)*10) | 24((23+1)+(0*100)) | 。。。 |
203 | 21 | 20(2*10) | 100((0+1)*100) | 。。。 |
213 | 22 | 24(2*10+4) | 100((0+1)*100) | 。。。 |
223 | 23 | 30((2+1)*10) | 100((0+1)*100) | 。。。 |
由以上数据分别对十位和百位进行分析,若abc表示一个三位数,对十位进行分析,那么:
- 若b=0,则十位为1的个数为a*10;
- 若b=1,则十位为1的个数为a*10+c+1;
- 若b>1,则十位为1的个数为(a+1)*10;
推广:若abcde表示任意位数的整数,对其中c位进行总结,那么:
- 若c=0,则c位为1的个数为ab*(c位);
- 若c=1,则c位为1的个数为ab*(c位)+de+1;
- 若c>0,则c位为1的个数为(ab+1)*(c位);
那么,就可以根据这个规律,找到1出现的个数。
三、源代码
1 // search1.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include"iostream" 6 using namespace std; 7 int main() 8 { 9 int num; //要输入的数据 10 int tag=1; //从个位开始计算 11 int count=0; //计数 12 int heigher,cur,less; //定义当前位数据cur和比他高的位heigher,以及比他低的位less 13 cout<<"请输入数据:"; 14 cin>>num; 15 while(num/tag!=0) 16 { 17 heigher=num/(tag*10); //当前位的高位 18 cur=(num/tag)%10; //当前位 19 less=num%tag; //当前位的低位 20 switch(cur) 21 { 22 case 0: 23 count=count+heigher*tag; 24 break; 25 case 1: 26 count=count+heigher*tag+less+1; 27 break; 28 default: 29 count=count+(heigher+1)*tag; 30 break; 31 } 32 tag=tag*10; 33 } 34 cout<<"1出现的个数为:"<<count<<endl; 35 return 0; 36 }
四、实验结果
五、实验分析
最近在看一本书,叫《你得灯亮着吗》,讲的就是应该如何正确的分析处理问题,就像这个题一样,我们很容易就会想到使用枚举的方式,并且解决方法也很简单,但是,这真的使我们想要的吗?不是,我们需要的是高效的准确的方法,虽然最简单的办法一般不会有错误,但我们大多数情况下,需要的是效率加正确性,那么如何是两者兼顾,就要探究问题的规律了。但是问题的规律不是那么容易找的,所以还是要在平时多多积累,只有好的基础,才能更好的思考问题,不然,基础都不会,又怎么去寻找更好的解决方法呢。
时间: 2024-10-04 23:36:09