问题 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; }
有更好的解法也可以告诉我。
(主要是写给自己看,当回忆录)