筛质数(埃氏、欧拉筛)

埃氏筛

 原理:一个数如果不是小于等于它的所有质数的倍数,那么这个数就是质数,质数的倍数一定都是合数根据以上原理,可以把题目已给范围内所有质数筛选出来,只需遍历所有数,把质数的倍数去除(标记为false),并且从前往后遍历的过程中每对一个质数进行以上操作,下一个为没被筛出的数一定也为质数,因为下一个数前面的所有质数的倍数都被去除了,这个数仍然留着说明这个数不是小于等于它的所有质数的倍数,因此一定是质数,举例:

初始时2为质数,把所有2的倍数去除后,遍历到下一个没有去除的3,3一定是质数,因为它不是小于它的所有的质数(也就是2)的倍数

接着把3的倍数去除,下一个没去除的5同样一定是质数,就这样慢慢的把范围内所有合数去除最终筛选出质数

问题:
根据上图可知考虑不同的质数时会去除重复的数(上图打×的数),虽然不影响结果,但会增加复杂度

优化:
1.遍历每个质数时可以从质数的平方开始去除,例如i=3时,可以从j=9开始去除,因为小于 i*i 的合数 j 一定有一个小于 i 的质因子。可以用反证法证明:(合数一定能拆分成几个质数的乘积)如果小于 i*i 的合数 j 没有小于 i 的质因子,那么合数 j 至少是两个 ≥i 的数的乘积,这与j<i*i矛盾.

2.有的题目遍历i的时候如果写成以下形式可能会出现下标越界:
for(int j=i*i;j<MX+1;j+=i){   
    is_primes[j]=false;  //质数的倍数都标记为合数
}
//遍历时可能会有i*i>MX的情况,因此可以让j遍历i的倍数

3.进一步优化-欧拉筛(线性筛)

代码:

int MX;  //根据数据范围确定
vector<bool> is_primes(MX+1,true);   //[0,MX]区间内所有质数为true

//C++11 lambda表达式,初始化is_primes
auto init=[]{
    is_primes[1]=false; //1为合数
    for(int i=2;i<MX+1,i++){ //遍历[2,MX]所有数,排除合数
        if(is_primes[i]){  //若当前的i是质数
            for(int j=i;j<MX/i+1;j++){ //遍历i的倍数,可以防止越界
                is_primes[i*j]=false;  //质数的倍数都标记为合数
            }
        }
    }
    return 0;
}();

欧拉筛-每个合数只被划掉一次

原理:每个数乘以小于等于它本身的所有质数得到的合数被划掉,就可以划掉所有合数,但是会有重复划掉的情况,进一步优化,划掉每个数乘以小于等于它本身的最小质因子的质数得到的合数,不会有重复去除的情况,例如:

过程:遍历2把2加入primes,去除2*2=4,遍历3把3加入primes,去除3*2=6,3*3=9,遍历4,4不是质数不加入primes,4的最小质因子是2,因此只需要去除primes中<=2的质数和它相乘得到的合数4*2=8,因为4的最小质因子是2,它乘以任何数得到的数最小质因子也一定是2,质因子是2的数会在之后被清除掉,所以不用再重复考虑(考虑6的时候6*2=12),这就是不重复去除的原理

int MX;  //根据数据范围确定
vector<bool> is_primes(MX+1,true);   //[0,MX]区间内所有质数为true
vector<int> primes; //加入质数

//C++11 lambda表达式,初始化is_primes
auto init=[]{
    is_primes[1]=false; //1为合数
    for(int i=2;i<Mx+1,i++){ //遍历[2,MX]所有数,排除合数
        if(is_primes[i])  //若当前的i是质数
            primes.emplace_back(i);
        //每个数i只乘以小于等于它的最小质因子(lpf[i])的所有质数,就不会重复去除
        for(int j=0;j<primes.size();j++){ //遍历之前所有的质数
            if(primes[j]*i>MX)  //越界
                break;
            is_primes[i*primes[j]]=false;
            if(i%primes[j]==0)  //碰到的第一个除的尽的质数就是最小质因子,碰到最小质因子直接退出
                break;
        }
    }
    return 0;
}();

选择:
在题目所数的范围比较小的时候可以使用埃氏筛,因为欧拉筛中有取模运算,反而会让运算时间更长,但当数的范围特别大的时候,去除的重复合数个数变多,埃氏筛就会比欧拉筛用时长

 [2614. 对角线上的质数](https://leetcode.cn/problems/prime-in-diagonal/) 1375
 [3115. 质数的最大距离](https://leetcode.cn/problems/maximum-prime-difference/) 1294
 [2523. 范围内最接近的两个质数](https://leetcode.cn/problems/closest-prime-numbers-in-range/) 1650
 [762. 二进制表示中质数个计算置位](https://leetcode.cn/problems/prime-number-of-set-bits-in-binary-representation/) 1383
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值