筛质数 朴素筛法 埃氏筛法 线性筛法

文章介绍了三种不同的质数筛法:朴素筛法的时间复杂度为O(nlogn),埃氏筛法优化到O(nloglogn),线性筛法则进一步优化到O(n)。线性筛法的关键在于每次都用最小质因子筛,确保每个数只被筛一次,通过避免不必要的计算提高了效率。

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

朴素筛法 O(nlogn)

不管是质数还是合数,都筛掉他们的倍数

int get_prime(int k)
{
    //for(int i=2;i<=k/i;i++)  这里需要都筛一遍
    for(int i=2;i<=k;i++)
    {
        if(st[i]==0) prime[cnt++]=i;
        for(int j=i+i;j<=k;j+=i)
        {
            st[j]=1;
        }
    }
    return cnt;
}

时间复杂度分析:
n 2 + n 3 + . . . + n n − 1 + n n = n ∗ ( 1 2 + 1 3 + . . . + 1 n − 1 + 1 n ) \frac{n}{2}+ \frac{n}{3}+ ...+ \frac{n}{n-1}+ \frac{n}{n} =n*(\frac{1}{2}+ \frac{1}{3}+ ...+ \frac{1}{n-1}+ \frac{1}{n} ) 2n+3n+...+n1n+nn=n(21+31+...+n11+n1)
括号内为调和级数,时间复杂度可记为O(nlogn)

埃氏筛法 O(nloglogn)

只筛掉质数的倍数

int get_prime(int k)
{
    for(int i=2;i<=k;i++)
    {
        if(st[i]==0)
        {
             prime[cnt++]=i;
            for(int j=i+i;j<=k;j+=i) st[j]=1;
        }
    }
    return cnt;
}
线性筛法O(n)

每次都用最小质因子筛,保证每个数只会被筛一次

利用1 ~ j个质数与当前的i,筛掉prime[j] * i,每次遍历1 ~ j个质数,与当前的i相乘

🎈🎈🎈问题是如何保证prime[j]prime[j]*i的最小质因子?

i%prime[j]!=0时:说明还没有执行if(i%prime[1~j-1]==0) break;也就是i并没有小于prime[j]的质因子,当前prime[j]*ii并没有小于prime[j]的质因子,所以prime[j]prime[j]*i的最小质因子

i%prime[j]==0时:i可以写成k*prime[j]prime[j+1]*i可以写成prime[j+1]*k *prime[j],所以往后遍历到的都不会是最小质因子,那后面的会如何筛掉?后面的在i=k时就被筛掉了,也就是在前面就被筛掉了

int get_prime(int k)
{
    for(int i=2;i<=k;i++)
    {
        if(st[i]==0) prime[cnt++]=i;
        //for(int j=0;j<=k/prime[j];j++)
        for(int j=0;prime[j]<=k/i;j++)
        {
            st[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
    return cnt;
}

🎈🎈🎈有一个问题是for(int j=0;prime[j]<=k/i;j++)是如何保证prime[j]中的j<=cnt的??? (如果j>cnt那么prime数组中的数还没有添加进去,全为0,这样就会没有意义)

分析:

​ 如果当前i为质数:那么i一定会被存到prime[j]中,当prime[j]=i时,满足i%prime[j]==0,会break

​ 如果当前i为合数:那么一定会有小于i的质数满足i%prime[j]==0

​ 所有综上:跳出循环的条件一定会满足prime[j]<=i,而<=i的质数肯定都被筛过了, 所以这样是合理可行的。if(i%prime[j]==0) break 保证了程序会在合适的时机跳出循环

🎈🎈🎈还有一个问题就是前面素数个数很少的时候,即j很小,prime[j]*i会不会漏掉,就是前面我们得到的素数个数很少,我们会不会漏掉?

其实不会,根据上一个问题的分析发现,每次prime[j]并不会用完,当i%prime[j]==0时,就会break

prime[1~j] i=1

prime[1~j] i=2

prime[1~j] i=3

prime[1~j] i=4

prime[1~j] i=n

这个过程中prime[j]与每一个i都组合过,当不符合条件时就停止,所以不会漏掉

这个算法理解起来有种玄学的味道…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值