线性筛质数
在之前的一篇筛质数的文章中只解释了埃式筛质数的方法,没有解释线性筛质数的方法
我们先看一下线性筛质数的代码
【例题】
给定一个正整数 n,请你求出 1∼n 中质数的个数。
输入格式
共一行,包含整数 n。
输出格式
共一行,包含一个整数,表示 1∼n 中质数的个数。
数据范围
1≤n≤ 1 0 6 10^6 106
输入样例:
8
输出样例:
4
java
import java.io.*;
import java.util.*;
public class Main {
static final int N = 1000010;
static int prime[] = new int[N];
static boolean st[] = new boolean[N];
static int idx;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
function(sc.nextInt());
System.out.println(idx);
sc.close();
}
public static void function(int n) {
for(int i = 2; i<= n; i++) {
//如果i不是合数,则i为质数
if(!st[i]) {
prime[idx++] = i;
}
//从小到大枚举质数,循环条件为prime[j] <= n / i的原因是在循环体里面用prime[j]筛掉prime[j] * i的质数
for(int j = 0; prime[j] <= n / i; j++) {
st[prime[j] * i] = true;
if(i % prime[j] == 0) {
break;
}
}
}
}
}
在这个代码中st
数组记录的是合数,prime
数组记录的是质数
其中每次都是从小到大枚举质数,所以会有两种情况
-
情况1
i % prime[j] == 0
在这种情况下,
prime[j]
一定是质数假设存在一个比
prime[j]
更小的质因子prime[k]
能整除i
,那么在之前遍历到prime[k]
时,就会因为i
能被prime[k]
整除而提前跳出内层循环,不会到prime[j]
这一步,所以当i % prime[j] == 0
时,prime[j]
是i
的最小质因子。因为
pj
是质数,且pj
是i
的最小质因子,对于pj * i
这个数,显然pj
是它的质因子。并且不存在比pj
更小的质因子能同时整除pj
和i
,所以pj
是pj * i
的最小质因子 。 -
情况2
i % prime[j] != 0
在这种情况下,
prime[j]
一定比i
的最小质因子还小, 因为primes
数组里的质数是从小到大排列的。如果i
存在比prime[j]
小的质因子,那么在之前遍历到那个更小的质因子时,就会发现它能整除i
,即i
对那个更小的质因子取模为0
。而且在这种情况下,
prime[j]
也一定是prime[j] * i
的最小质因子
对于一个合数x
,我们假设已经确定了它的最小质因子prime[j]
。
在筛法的循环过程中,我们会从较小的数开始枚举i 。当枚举到(i = x / prime[j]) 时,此时(prime[j] * i = x) 。这是因为根据数的因数关系,如果prime[j] 是x 的最小质因子,那么x 可以表示为(x = prime[j] * k) (k 为整数 ),这里的k 就是(x / prime[j])