数字之谜

数字之谜



问题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--;
		}

结果:

程序运行结果如下



即求出的最大值为途中所示。








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值