Sieve of Prime Number
如何判断一个数是不是质数,现在求区间 $[1,1e7]$ 内所有质数,学习「埃式筛法」和「欧拉筛法」之前,先介绍下暴力筛选。
可借此题验证下:204. 计数质数
1. 暴力筛选
0
表示质数,1
表示合数。
1 | static final int N = 1e7 + 5; |
2. 埃式筛法
这种方法无疑是最慢的,换一种思路:一个质数的倍数一定是合数。
所以假设 P 是质数,我们可以筛选掉区间 $[1,1e7]$ 中所有 P 的倍数。
为什么这样能筛去所有的合数呢,因为一个合数一定能被分解为几个质数的幂的乘积,并且这个数的质因子一定是小于它本身的,所以当我们从小到大将每个质数的倍数都筛去的话,当遍历到一个合数时,它一定已经被它的质因子给筛去了。
1 |
|
我们还可以对其进行优化:
- 我们会先筛 2 的所有倍数,然后筛 3 的所有倍数,但筛除3的倍数时,我们还是从 3 的 2 倍开始筛,其实 $3 * 2$ ,已经被 $2 * 3$ 时筛过了。又比如说筛 5 的倍数时,我们从 5 的 2 倍开始筛,但是 $5 * 2$ 会先被 $2 * 5$ 筛去,$5 * 3$ 会先被 $3 * 5$ 筛去,$5 * 4$ 会先被 $2 * 10$ 筛去,所以我们每一次只需要从 $i * i$ 开始筛,因为 $(2,3,…,i - 1)$ 倍已经被筛过了。
- 另外,判断一个数 n 是不是质数,我们只需要判断 $[2,\sqrt{n}]$ 内有没有它的因子,在筛选合数时,我们也可以这样做,因为一个合数的最小质因子一定小于等于 $\sqrt{n}$。
优化后的埃式筛法:
1 |
|
时间复杂度可以近似看成 $O(n)$
但是我们还可以更快,那就是欧拉筛,又称为线性筛。
3. 欧拉筛法/线性筛法
欧拉筛的核心思想就是确保每个合数只被最小质因数筛掉,或者说被合数的最大因子筛掉。
比如 $120 = 2^3 * 3 * 5$,120 会被 2 筛一次,3 筛一次,5 筛一次。
多做了两次不必要的操作,如何确保 120 只 2 筛选掉。
时间复杂度:$O(n)$
1 |
|