厄拉多塞筛素数筛选算法
2022年12月31日 · 197 字 · 1 分钟
厄拉多塞筛算法(Eratosthenes Sieve)是一种求素数的方法,由古希腊数学家厄拉多塞提出。它的原理是,给定一个数 n,从 2 开始依次将 $\sqrt n$ 以内的素数的倍数标记为合数,标记完成后,剩余未被标记的数为素数(从 2 开始)。如此可省去检查每个数的步骤,使筛选素数的过程更加简单。
算法
厄拉多塞筛算法具体步骤如下:
- 读取输入的数 n,将 2 到 n 的所有整数记录在表中
- 从 2 开始,划去表中所有 2 的倍数
- 由小到大寻找表中下一个未被划去的整数,再划去表中所有该整数的倍数
- 重复第(3)步,直到找到的整数大于$\sqrt n$为止
- 表中所有未被划去的整数均为素数
朴素的素数筛选算法如下:对给定的数字$i$,设定数字$j$从$2$遍历到$\sqrt i$,如果中间$i$能整除$j$,则$i$不是素数。该方法的时间复杂度为$O(n\sqrt n)$ ,$n$是数组长度,外层循环需要遍历$n$次,内层循环需要遍历$\sqrt n$次。
而厄拉多塞筛算法的时间复杂度为$O(n log(log(n)))$。
举例
这是一张来自维基百科的算法示意图。
- 先从2开始遍历,将2的倍数(2,4,6,8,…)标记为为非素数
- 继续遍历,当前数字是素数时,继续将当前数字的倍数标记为非素数
- 直到所有数字标记完,重新标记数组,未被标记的就是素数
算法题
Leetcode 204. 计数质数
给定整数 n
,返回 所有小于非负整数 n
的质数的数量 。
示例 1:
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:
输入:n = 0
输出:0
示例 3:
输入:n = 1
输出:0
代码实现
class Solution2 {
// 厄拉多塞筛素数筛选算法
// 1. 准备O(n)的数组,标识数字是否是质数,初始情况下全部是质数
// 2. 从2开始遍历到sqrt(n),如果数字是质数,则i*i开始,后面i的倍数全是合数
// 3. 从[2,n)筛选质数并统计
public int countPrimes(int n) {
if (n < 2) {
return 0;
}
var isPrime = new boolean[n];
Arrays.fill(isPrime, true);
for (int i = 2; i * i < n; i++) { // 遍历一半即可
if (isPrime[i]) { // 如果是质数,则将i平方开始的所有i的倍数设为合数
// 任意素数x的倍数有:2x, 3x, 4x, ..., x*x, (x+1)*x, ...
// 任意小于x*x的倍数都被之前的素数筛过滤过,如:2 过滤 2x, 4x, ...,3 过滤 3x, ...
for (int j = i * i; j < n; j += i) {
isPrime[j] = false;
}
}
}
var count = 0;
for (int i = 2; i < n; i++) {
if (isPrime[i]) {
count++;
}
}
return count;
}
}
时间复杂度: $O(nlog(log(n)))$。时间复杂度证明过程有点复杂,我暂时还没消化。
空间复杂度:$O(n)$。需要长度为$n$的数组标记是否素数。