问题1:从1,2,3,····,n,共有多少个1数字?
例子从1-12,共有5个1数字,结果如下
思路
我们知道最大值N,
暴力法:就是计算1-n的每个数里还有1数字的个数,然后相加即可,时间复杂度O(N*(每个数字的位数长度))
对于每个数,计算它还有1数字的个数的思路先取来每位数字,对于一个数m,它的位数长度我们用length(int m)方法来求得
1)计算整数位数思路如下
// function 23: 计算一个整数有多少位数 // 输入: 一个整数 // 输出:整数的位数 int IntData_number(int N) { int data = N; int length = 0; while(data != 0) { data = data/10; length ++; } return length ; }2)抽取整数第i位操作思路如下
n = pow(10.0,i); bit = ( N % n ) / (n/10) ;3)然后对每一位判断是不是1即可
优化法:首先我们能得到最大数N的位数为length(用到的方法如上)
然后我们转换问题:数字的组合排列问题思路如下
int f(int N) { int result = 0; int length = 0; int bit = 0; int n = 0; int now = 0; if( N>0 ) { // 对于长度为1 的数字处理 if(N<=9) return 1; length = String::IntData_number(N); //对于长度>1的数字处理 // 对个位处理 // 如果个位是 0,则高位有( n/10 +1(算上0) - 1(因为个位是0,最大的数不能要))个选择 if( N%10 == 0 ) result = N/10 ; // 否则 则高位有 ( n/10 +1(算上0))个选择 else result = N/10 +1; // 对2 -(n-1)位处理 for(int i = 2;i<length;i++) { //获取第i位数字 n = pow(10.0,i); bit = ( N % n ) / (n/10) ; //第i位为 0,则高位的选择为 N/ (10^i) +1-1(因为包括0,不包括最高位) //低位选择为 10^(i-1) if(bit == 0) { now = (N/n )*(n/10) ; } //第i位为1,则高位的选择为 N/ (10^i) +1-1(因为包括0,不包括最高位) //低位选择为 10^(i-1) //同时还得加上高位为最大时,低位上的选择N%(10^(i-1))+1(因为包括 0) else if(bit == 1) { now = (N/n )*(n/10) ; now += N % (n/10) +1; } //第i位>1,则高位的选择为 N/ (10^i) +1(因为包括0,包括最高位) //低位选择为 10^(i-1) else { now = (N/n+1)*(n/10) ; } result += now ; } // 对最后一位处理 if(length > 1) { bit = N /(int)(pow(10.0,length-1)); // 对于最后一位是 1,则其后面的数+1(因为包括0) if( bit==1 ) { result += N % (int)(pow(10.0,length-1)) + 1; } // 否则 为 10^(n-1),每一个都有10个取值选择 else if(bit > 1) { result += (int)(pow(10.0,length-1)); } } } //else cout<<"N<=0"<<endl; return result; }
优化法运行结果
部分截图如下
程序注释 每一行第一个数为N,第二个数为问题答案
问题2:
对于问题1,求出f(N),现在问题求出f(N)= N时N的最大值
对于数学来说,N值会很大,有可能超出int最大值,也可能不超出,这个我也没法证明
我的思路是从int最大值逐渐减小然后求得符合条件的N值
思路:
int i = numeric_limits<int>::max(),m; while(true) { m = f(i); if(i == m) { cout<<i<<" "<<m<<endl; break; } i--; }
结果:
程序运行结果如下
即求出的最大值为途中所示。
数字之谜
时间: 2024-11-02 23:38:11