幸运数字II (类似二分?)石油大

问题 I: 幸运数字II

时间限制: 1.000 Sec  内存限制: 128 M

题目描述

数字4和7是幸运数字,而其他的都不是幸运数字。一个整数是幸运数字,当且仅当它的十进制表示只包含幸运数字。
现在让你给出第K大的幸运数字。

输入

第一行一个整数K(1<=K<=1,000,000,000)

输出

第K大的幸运数字。

样例输入 Copy

1

样例输出 Copy

4

根据题意给出的数据范围,数据的大小应该是在30位左右,如果用最简单的暴力遍历肯定会超时,下面是我在做这个题时的想法思路。

一、找到第k个数对应的数字位数的最小数(感觉会超时,所以后面换了思路,不想看这个的可以直接看完第一段再看二)

        找到第k个数对应的数字的位数count是多少,因为由题意可知,数字的位数不同,对应的数字个数也不同。例如,1位的幸运数字个数有2个,2位的有4个,3位的有8个,用一个数组s[n]来维护n位及小于n位的时候,共有几个数字,所以s[1]=2,s[2]=6,s[3]=14....。找到一个值count使得s[count]>k,所以当前的数字的位数应该是count;

        然后使用一个循环(这个应该都会),获得当前位数的最小数字,例如:5位最小数字,44444。同时还要更新当前的k值为 k = k - s[count-1],从当前一组数字开始的第k个数。然后开始遍历,如果有一个数他的每一位都是4或者7,就把计数器加1,直到等于k。(个人感觉一定会超时,所以放弃了这个做法

long long int k , n, count = 0 , l = 0 ,x = 0 ,s[50] = {0};
cin>>k;
while(k > x){
	count ++;
	x = x + pow(2,count);
	s[count] = x ;
}
k = k - s[count-1];

二、利用类似二分的思想(自我感觉)

        把位数相同的数据分成一组,即2位有4个,3位有8个,四位16个。

        因为要输出的数据串中只包含4和7,想一想什么情况这一位数字是4,什么情况下会是7。

        显而易见,只有两种情况,要么是4要么是7,那是不是就意味着在第n组数字(s[count]-s[count-1])的前半部分是以4开头,后半部分以7开头。例如第三组数字:

        1         2         3         4         5         6         7         8 

        444      447    474      477     744      747     774      777

很明显,在1-4,前半部分的第一位全是4,5-8后半部分的第一位全是7,那么如果第一位固定了之后,对于第二位,是不是也可以利用同样的方法确定这一位是4还是7?图中显而易见,是符合这个规律的。所以现在的问题就转化成了求出当前组中数字的数量n,n/2就是判定4和7的中间值,还有求出第k个数字在当前组中是第几个。这时我才发现原来前面我已经把需要的相应的操作写出来了,这不正是编程的乐趣所在吗?  

        接下来的代码就完全没难度了。完整代码如下:

#include<iostream>
#include<math.h>
#include<map>
#include<algorithm>
using namespace std;
int main(){
long long int k , n, count = 0 , l = 0 ,x = 0 ,s[50] = {0};
cin>>k;
while(k > x){
	count ++;						//求出数字的位数
	x = x + pow(2,count);
	s[count] = x ;					//保存共有几个数字
}
k = k - s[count-1];
n = (s[count] - s[count-1]) / 2;
while(l < count){					//有几位就输出几位
	if(k <= n)						//小于的话就输出4
		{
			n = n / 2;				//更新中间值
			cout<<4;
		}
	else{
		k = k - n;					//更新k的值
		n = n / 2;					//更新中间值
		cout<<7;
	}
	l ++;
}
return 0;
}

有更好的解法也可以告诉我。

(主要是写给自己看,当回忆录)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>