Eular质数筛法 欧拉筛
相比于时间复杂度为 O(n(lgn)2) 的埃氏筛法,Eular 质数筛法就显得非常短小精悍。
欧拉筛的时间复杂度为 O(n),是一种空间换取时间的算法。
一、空间需求
欧拉筛需要两个数组:
① prime[],用来存储素数。
② is_prime[],用来表示 i (i <= n) 是否为质数。
二、步骤
① memset(is_prime, 1, sizeof(is_prime))
将 is_prime 数组全部置为 1。
② 外层循环LOOP:for( i = 2 -> n)
遍历每个数字 i 。
③ 若 i 为质数,那么将 i 加入 prime[] 数组。
④ 内层循环LOOP:for(j = 0 -> prime.length)
不论 i 是否为质数都会进入内层循环。
⑤ 若 i * prime[j] > n 则 break 内层循环LOOP。
否则,is_prime[ i * prime[j] ] = 0
把 i * prime[j] 标记为合数。
⑥ 若 i % prime[j] == 0 则 break 内层循环LOOP,继续外层循环LOOP。
三、核心
欧拉筛效率这么高的核心就在于上面的第⑥点,
若 i % prime[j] == 0 则退出内层循环LOOP。
为什么可以直接退出呢?后面的数就不用继续筛选了吗?
是的,当 i % prime[j] == 0 时,说明 i = prime[j] * k
对于 prime[j] 后面的元素 prime[next_j],
prime[next_j] * i 将会在之后的筛选中被筛掉,无需重复。
因为 prime[next_j] * i = prime[next_j] * (prime[j] * k)
= prime[j] * (prime[next_j] * k)
例如:
prime[] = {2, 3} i = 4
2*4 = 8 被筛 此时 4%2 == 0 break
3*4 = 12 这次不筛
因为 4 = 22, 故 3 * (22) = 2 * (3*2)
在 3 * 2 = 6 = i 时会筛掉12。
参考代码:
int *prime;
int *is_prime;
void getPrime(int n){
for(int i = 0; i <= n; i++){
is_prime[i] = 1;
}
int cnt = 0;
for(int i = 2; i <= n; i++){
if(is_prime[i]){
prime[cnt++] = i;
}
for(int j = 0; j < cnt; j++){
if(prime[j]*i > n){
break;
}
is_prime[prime[j]*i] = 0;
if(i%prime[j] == 0){
break;
}
}
}
}
【END】感谢观看