四、题目:第几个幸运数字
到x星球旅行的游客都被发给一个整数,作为游客编号。
x星的国王有个怪癖,他只喜欢数字3,5和7。
国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。
我们来看前10个幸运数字是:
3 5 7 9 15 21 25 27 35 45
因而第11个幸运数字是:49
小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505是第几个幸运数字。
- 分析思路:
起初用暴力解法除3,5,7发现没有运行结果,思路是错误的,原因是迭代次数太多
这道题目类似于素数的筛选
- check 试除法(给定1个数字n:1-根号n;能不能整除根号n)
- 生成法:筛选
题中幸运数字3,5,7,9,15,21,25,27,35,45
3×3=9
3×5=15
3×7=21
3×9=27
5×5=25
5×7=35
5×9=45
7×7=49
会发现有重复的3×7=21和7×3=21;
5×7=35和7×5=35
生成法:用队列 工具用set
需要考虑先排序后去重
C++:用set
JAVA:用TreeSet
- 错误代码
#include<iostream>
using namespace std;
int main(){
LL ans=0;
for(int i=3;i<=MAX;i++){
int x=i;
while(x%3==0) x/=3;
while(x%5==0) x/=5;
while(x%7==0) x/7;
if(x==1)
ans++;
}
cout<<ans<<endl;
}
代码:C++
#include<iostream>
#include<set>
using namespace std;
typedef long long LL;
const LL MAX=59084709587505;
int main(){
int a[3]={3,5,7};
LL tou=1;//最初队列头部设为1
set<LL> s;
while(true){
//队列头部,完成3个数的插入
for(int i=0;i<3;i++){
LL tt=tou*a[i]; //分别乘以3,5,7
if(tt<=MAX) //乘出的数小于MAX就存入set
s.insert(tt);
}
tou=*(s.upper_bound(tou)); //新的头部,从set中选择比tou大的最小的数字
if(tou>=MAX)break
}
cout<<s.size()<<endl;
return 0;
}
- 代码:JAVA
package luckynum;
import java.util.TreeSet;
public class Luckynum {
final static long MAX=59084709587505L;
public static void main(String[] args) {
int[] a= {3,5,7};
long tou=1;
TreeSet<Long> s=new TreeSet<Long>();
while(true) {
for(int i=0;i<3;i++) {
long tt=tou*a[i]; //t分别乘以3,5,7
if(tt<=MAX)
s.add(tt);
}
tou=s.higher(tou); //从set中选择比tou大的最小数字
if(tou>=MAX)break;
}
System.out.println(s.size());
}
}
答案:1905