欧拉筛——找出 [2, n] 区间内的所有素数
欧拉筛:
欧拉筛(线性筛)是一种用于高效找出n范围内所有素数的算法,时间复杂度为 O(n),其核心优势在于避免了对同一个合数的重复标记。
算法原理
欧拉筛的核心思路是让每个合数只被它的最小质因数筛去。
简单的讲就是找出当前未找出的最小素数,然后顺便把所有以该素数为最小质因数的数剔除掉。
为了避免重复剔除同一个数所导致的时间浪费,所有我们规定一个剔除原理,即让每个合数只被它的最小质因数筛去。这里是为了避免比如5 * 7 =35这种情况,35只被5剔除,不被7重复剔除。
欧拉筛是线性的,从小到大的。
欧拉筛一定会遍历每一个数(单是把素数收录就需求遍历)。
欧拉筛可以分为两步
- 对当前数 i 的素性判断,决定是否收录。
- 对未被遍历的数进行剔除。
vector<int> eulerSieve(int n) {
vector<bool> is_prime(n + 1, true);// 初始化标记都是素数
is_prime[0] = is_prime[1] = false;// 0 和 1 不是素数
vector<int> primes;
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
primes.push_back(i);// 如果 i 是素数,将其加入 primes 向量
}
// 遍历已找到的素数,进行剔除
for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
is_prime[i * primes[j]] = false;// 标记 i * primes[j] 为合数
if (i % primes[j] == 0) {// 当 i 能被 primes[j] 整除时,停止遍历
break;
}
}
}
return primes;
}
如果i%prime[ j ]=0则i是某个已经确定的素数prime[ j ]的倍数,则i*prime[ j ]应该由prime[ j ]来去除.
for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
is_prime[i * primes[j]] = false;// 标记 i * primes[j] 为合数
if (i % primes[j] == 0) {// 当 i 能被 primes[j] 整除时,停止遍历
break;
}
}
这里我们需要关注的主体并不是primes【j】而是 i ,因为这个循环的目的是去除每个素数的i倍,所以去除了i*primes【j】之后应当停止,因为primes【j】后面每个素数 * i都是在给以primes【j】为最小质因数的数剔除。
i*prime(next)=k* prime(now)*prime(next),这是一个以prime(now)为最小质因数的合数,而不是prime(next)为最小质因数的合数。所以我们直接break,此后的所有prime(next)都没有必要再乘i了。后面的素数都被primes[j]给筛了

浙公网安备 33010602011771号