埃拉托色尼筛(Sieve of Eratosthenes)能在 O(n log log n) 时间内找出 [2, n] 内的所有素数。思路朴素而漂亮:
找到一个还没被划掉的数
p,它必然是素数;然后把它的所有倍数(p², p²+p, p²+2p, ...)都划掉。
为什么从 p² 开始?因为 p × k(k < p)一定在某个更小的素数那一轮就被划过了。
实现要点
for (int p = 2; p * p <= n; ++p) {
if (isPrime[p]) {
for (int i = p * p; i <= n; i += p) isPrime[i] = false;
}
}
外层循环只到 √n —— 任何合数 c ≤ n 必有一个因子 ≤ √c ≤ √n,所以 √n 之后的数如果还没被划掉就一定是素数。
复杂度
- 时间:O(n log log n) —— 比朴素的 O(n √n) 快非常多
- 空间:O(n) 的标记数组
在动画里看什么
- 深蓝:当前选中的素数
p - 暖红:正在被划掉的合数
i = k·p - 绿色:已经确认是素数
- 灰色 + 删除线:已经被划掉的合数
- 数表分 10 列排列,便于看清楚”每隔 p 个划一个”的节奏