算法笔记(13):埃氏筛与欧拉筛

本文介绍了两种高效的质数筛选算法——埃氏筛和欧拉筛。埃氏筛通过标记合数及其倍数来筛选质数,但存在重复筛选的问题,时间复杂度为O(nlg⁡lg⁡n)O(nlglgn)O(nlglgn)。欧拉筛则通过找到每个数的最小质因子避免重复筛选,达到O(N)O(N)O(N)的时间复杂度。这两种算法在解决质数相关问题时能显著提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在刷算法题的时候经常遇到与质数有关的问题,而普通方式筛选质数十分耗时(判断n是否为质数的O(n)O(n)O(n)O(n)O(\sqrt{n})O(n)比较耗时),故今天学习了埃氏筛和欧拉筛两种算法。

埃氏筛

int prime[N];//记录[1,N]中所有质数,从小到大排序
int vis[N];//vis[i]=1当i是合数
vis[0] = vis[1] = 1;
for (int i = 2; i <= N; i++)
{
  	if (!vis[i])
    {
        prime[cnt++] = i;
       	for (int j = i * i; j <= N; j+=i)
             vis[j] = 1;
    }
}

算法核心思想

遍历[1,N][1,N][1,N],对于每一个质数,记下它并将它的倍数设置为合数。

算法需要考虑的两个问题:

  1. 能否保证vis[i]的准确性
  2. 筛选是否完全

先来考虑第一个问题
iii为质数时,vis[i]一定为0(只有质数的倍数的vis被设为1,显然质数的vis都为0);
iii为合数时,则由算术分解定理,i可以被拆分为p1k1×p2k2×...×pnknp_1^{k_1}\times p_2^{k_2}\times...\times p_n^{k_n}p1k1×p2k2×...×pnkn,其中p为质数。再进一步,则有i=pmin×k=pmin+pmin+...+pmini=p_{min}\times k=p_{min}+p_{min}+...+p_{min}i=pmin×k=pmin+pmin+...+pmin,其中pminp_{min}pmin为i的最小质因子,意味着在前面的循环过程中vis[i]已经被赋值为1了。综上vis[i]是准确的。
再来考虑第二个问题
既然vis[i]数组是准确的,则遍历完成后即正确完成筛选。
算法缺陷
一个数可能被多次筛选,如30=2×15=3×10=5×6=...30=2\times 15=3\times 10=5\times 6=...30=2×15=3×10=5×6=...,这种重复筛选是无意义的
复杂度:O(nlg⁡lg⁡n)O(n\lg\lg n)O(nlglgn)

欧拉筛

int prime[N];//记录[1,N]中所有质数,从小到大排序
int vis[N];//vis[i]=1当i是合数
vis[0] = vis[1] = 1;
for (int i = 2; i <= N; i++)
{
    if (!vis[i])
        prime[cnt++] = i;
    for (int j = 0; j < cnt && prime[j] * i <= N; j++)
    {
        vis[i * prime[j]] = 1;
        if (i % prime[j] == 0)//降低复杂度的核心步骤
                break;
    }
}

算法核心思想

利用任何数都是可以分解为其最小质因数的x倍的性质来进行筛选,此处遍历的i是倍数

核心步骤的理解
在欧拉筛算法中,我们降低复杂度的方式就是去除重复筛选,而去重的方式就是我们只通过某个数的最小质因数的k倍来将这个数的vis置1,这样做使得任何数的vis都不会被重复置1。那么问题就是怎么保证prime[j]prime[j]prime[j]i×prime[j]i\times prime[j]i×prime[j]的最小质因数,易知我们只需要考虑i的最小质因子大于等于prime[j]prime[j]prime[j]就可以了,即在每次执行后都去判断prime[j]prime[j]prime[j]是否是i的质因子,是的时候则不用再去执行vis[i×prime[j+1]]vis[i\times prime[j+1]]vis[i×prime[j+1]](显然此时prime[j+1]prime[j+1]prime[j+1]已经不是i×prime[j+1]i\times prime[j+1]i×prime[j+1]的最小质因子了)

复杂度: O(N)O(N)O(N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值