一、实验题目
给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数出其中1的个数。
要求:
1、写一个函数F(N),返回1~N之间出现“1”的个数,例如:F(12)=5;
2、在32位整数范围内,满足条件的“F(N)=n”的最大的N是多少;
二、设计思路
考虑到时间复杂度,首先摒弃遍历的方法。
然后找规律:
通过分析Num每一位上的1的个数,将32位正整数的遍历简化为做多循环10次(因为32位无符号整数范围:0 - 4294967295,仅有10位),经过分析,我发现存在这样的规律:
每一位上都只有三种情况:0,1,2-9
第 i 位(个位算作第0位,十位算作第1位。。。。。):
0: Num/(10^(i+1))*(10^i)
1: Num/(10^(i+1))*(10^i)+Num%(10^i)+1;
2-9: (Num/(10^(i+1))+1)*(10^i)
可实现最大数:应该是4294967295,但实际不行,9位数是没问题的。
三、代码
1 // Finding_the_number_of_1.cpp 2 // by 梁世豪 3 // 2015/4/29 4 5 #include "stdafx.h" 6 #include "iostream" 7 #include "math.h" 8 using namespace std; 9 int main() 10 { 11 zailai: 12 unsigned long int max=0;//要查询的数 13 unsigned long int num=0;//结果 14 int n;//位数 15 int i=0; 16 int m=1; 17 int j=0; 18 int k=0;//判断本位上是0,1还是其他数 19 unsigned long int array[10]={0,0,0,0,0,0,0,0,0,0};//32位正整数最大10位数 20 cout<<"请输入要查询的正整数:"; 21 cin>>max; 22 cout<<"这个数的位数:"; 23 cin>>n; 24 for(i=0;i<n;i++) 25 { 26 m=1; 27 for(j=1;j<=i;j++) 28 { 29 m=m*10; 30 } 31 k=(max%(m*10))/m; 32 cout<<k<<endl; 33 if(k==0) 34 { 35 m=1; 36 for(j=1;j<=i;j++) 37 { 38 m=m*10; 39 } 40 array[i]=max/(m*10)*m; 41 cout<<"0有"<<array[i]<<endl; 42 } 43 else if(k==1) 44 { 45 m=1; 46 for(j=1;j<=i;j++) 47 { 48 m=m*10; 49 } 50 array[i]=(max/(m*10))*m+max%m+1; 51 cout<<"1有"<<array[i]<<"个"<<endl; 52 } 53 else 54 { 55 m=1; 56 for(j=1;j<=i;j++) 57 { 58 m=m*10; 59 } 60 array[i]=(max/(10*m)+1)*m; 61 cout<<"2-9有"<<array[i]<<endl; 62 } 63 num=num+array[i]; 64 } 65 66 cout<<"共有"<<num<<"个‘1’"<<endl; 67 goto zailai; 68 return 0; 69 }
四、运行截图
五、总结
喜欢这种游戏类的编程,结合老师的提示,总结了规律之后,终于把程序写出来了。