目录
题目描述
幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的"筛法"生成。
首先从 1 开始写出自然数 1,2,3,4,5,6,⋯
1 就是第一个幸运数。
我们从 2 这个数开始。把所有序号能被 2 整除的项删除,变为:
1 3 5 7 9 ⋯
把它们缩紧,重新记序,为:
1 3 5 7 9 ⋯
这时,3 为第 2个幸运数,然后把所有能被 3 整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被 3 整除!!删除的应该是 5,11, 17,⋯
此时 7 为第 3 个幸运数,然后再删去序号位置能被 7 整除的( 19,39,⋯)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ⋯
输入描述
输入两个正整数 m,n用空格分开 (m < n < 10^6)。
输出描述
输出位于 m 和 n 之间的幸运数的个数(不包含 m 和 n )。
输入输出样例
输入
1 20
输出
5
题目分析:列表枚举
1.照例先分析题目,幸运数是从1开始的,一直往后,然后1是第一个自然数,就不管他,让第一个幸运数从2开始,就是删除所有下标能被2整除的数。
2.这里看到需要频繁删除,首先排除数组来做(用数组做也不是不行),可以用列表。
3.然后看数据范围,它给的提示是 m和n,但是幸运数是从1开始的,也就是说我们需要填充1到n的数据进列表里面。然后删除完毕之后再判断m-n范围内的数据有多少即可。
4.因为列表的特性(删除了i,那么i的位置就会被i+1补上),所以我们删除要从末尾开始,依次往前删除,也就是 从len 到 1;
5.循环读取幸运数删除即可,每次拿到幸运数,通过一个方法,逆向删除所有能被该幸运数整除的下标即可。
AC代码(Java):
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//题目描述是很有问题,简单来说,就是这些幸运数是从1开始填充到N的,然后第一个幸运数为2,就是删除偶数位置的值
//然后第二个幸运数就是列表中的第三个数(列表我们额外填充一个0,这样1的下标就是1,模拟出了题目的情况)
int m = scan.nextInt();
int n = scan.nextInt();
scan.close();
List<Integer> list = new ArrayList<>();
//因为下标都是从0开始,我们为了模拟题目要求,多填充一个0
list.add(0);
//填充数据
for(int i = 1;i<=n;i++){
list.add(i);
}
//幸运数从1开始,直到列表的长度(超出列表的长度代表幸运数已经处理完了,接下来只需要统计m-n范围的数据即可)
int luck = 1;
while(luck<list.size()){
//处理一开始的特殊情况(第一个幸运数是1,那么就顺延到下一个,也就是2)
if(luck == 1){
delete(list,2);
}else{
delete(list,list.get(luck));
}
luck++;
}
//删除完之后遍历一下看看list剩余
int number = 0;
for(int i : list){
if(i>m && i<n){
number++;
}
}
System.out.println(number);
}
/*删除能被luck整除的下标*/
public static void delete(List<Integer> list,int luck){
//一般都是从末尾开始删除,不然会因为列表的特性(删了i位置的,i+1位置的会补上来)出错
int len = list.size()-1;
for(int i = len;i>0;i--){
if(i%luck == 0){
list.remove(i);
}
}
}
}