埃氏筛法与线性筛法(重点!!!)

作者 : XiaXinyu
日期 :2021-10-01

给定一个正整数 n,请你求出 1∼n 中质数的个数。

输入格式
共一行,包含整数 n。

输出格式
共一行,包含一个整数,表示 1∼n 中质数的个数。

数据范围
1≤n≤106
输入样例:

8

输出样例:

4

1.埃氏筛法

思路:将2—n中每一个数的倍数全部筛去,剩下的数就是2—n中的质数。

反证法证明:假设将2—n中每一个数的倍数全部筛去,剩下的数中有合数ai

由合数的基本概念可知那么ai一定是a1—ai-1中某个数的倍数,与假设矛盾

证毕

代码

import java.util.*;
public class Main{
    static int[] p = new int[1000010];
    static boolean[] s = new boolean[1000010];
    static int cnt = 0;
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for(int i = 2;i <= n;i ++){
            if(! s[i]){
                p[cnt ++] = i;
                for(int j = i;j <= n;j += i) s[j] = true;
            }   
        }
        System.out.println(cnt);
    }
}

时间复杂度:O(nloglogn)

2.线性筛法——重点

在前面的埃氏筛法中有很多数被重复删除多次,因为一个合数可能是多个质数的倍数,使用线性筛法可以避免这种情况并且将时间复杂度降低到O(n)

埃氏筛法核心原理:每个合数只会被它的最小质因子筛去

代码和思路:

//2.线性筛法
import java.util.*;
public class Main{
    static int[] p = new int[1000010];
    static boolean[] s = new boolean[1000010];
    static int cnt = 0;
    static void get_primes(int n){
        for(int i = 2;i <= n;i++){
            if(!s[i]) p[cnt ++] = i;            
            for(int j = 0;i * p[j] <= n;j ++){
                //1.p[j]是n的质因子,要确保i * p[j] <= n的原因是
                //删除大于n的合数没有意义
                s[p[j] * i] = true;
                if(i % p[j] == 0) break;       
               //2.当i % p[j] == 0时说明p[j]是i的最小质因子,那么p[j]也
               //  一定是p[j] * i的最小质因子
               //  当i % p[j] != 0是说明p[j]不是i的最小质因子,但是p[j]
               //  仍然是p[j] * i的最小质因子
               //  所以不论哪种情况p[j]都一定是p[j] * i的最小质因子
               
               //3.为什么当i % p[j] == 0是要跳出循环呢?
               // 因为如果不跳出循环的话,p[j + 1] * i 的最小质因子就不是
               // p[j + 1]了,因为i存在最小质因子p[j],这就导致了p[j + 1] * i
               //并不是被自己的最小质因子给删除的,违背了线性筛法的原理,造成了
               //重复删除的现象
               
               //4.为什么2-n之间的合数都会被删干净呢?
               // 因为每一个合数都存在一个最小质因子,就是这么简单!!!                              
                                               
            }
        }
        System.out.print(cnt);
    }
    
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        get_primes(n);
    }
}
线性筛法对第一次接触的初学者还是有点难度的

时间复杂度:O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiaXinyuuu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值