文章目录
- 前言
- 朴素筛法(纯暴力,O(n^2^))
- 埃式筛法(找出合数来确认质数, O(n*log(logn)))
- 欧拉筛法(线性筛选,O(n))
- 参考文章
前言
在学习Acwing c++蓝桥杯辅导课第八讲数论-1295. X的因子链时接触到了欧拉筛法,本章就从最原始的朴素筛法来开始到最终的欧拉筛法。
本章节的测试数据n为100万,问题围绕从去找寻指定[2, n]范围找到所有质数个数开始。
当前文章已收录到博客文件目录索引:博客目录索引(持续更新)
朴素筛法(纯暴力,O(n2))
思路:每判断一个n是否是质数,就去遍历[2, n - 1]来去看是否能够整除,若是都不能够整除表示其是一个质数。
复杂度分析:时间复杂度O(n2)
class Main {
    //朴素筛法:O(n^2^)
    public static boolean isPrime(int n) {
        for (int i = 2; i < n; i++) {
            if (n % i == 0) return false;
        }
        return true;
    }
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        //int N = (int) 1e6;
        int N = 100;
        int count = 0;
        for (int i = 2; i <= N; i++) {
            if (isPrime(i)) count++;
        }
        System.out.println(count);
        long endTime = System.currentTimeMillis();
        System.out.println("执行时间:" + (float) (endTime - startTime) / 1000 + "s");
    }
}
进一步来进行优化,实际上对于isPrime中遍历到的终点n实际上可以去进行开根号:
//朴素筛法优化:O(n^2^)
public static boolean isPrime(int n) {
    //开根号
    int sqt = (int) Math.sqrt(n);
    for (int i = 2; i <= sqt + 1; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

其他写法:
for (int i = 2; i <= n / i; i++)
   
//不推荐,i*i可能会出现溢出情况,建议通过上面的n / i来进行不会出现溢出
for (int i = 2; i * i <= n ; i++)
埃式筛法(找出合数来确认质数, O(n*log(logn)))
合数:合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
思路:首先去使用数组来存储所有的合数,接着来去判断对应的数字是否是质数。
时间复杂度:O(n*log(logn))
package com.changlu.java;
class Main {
    static int N = (int) 1e6;
    //筛选出所有的合数(为1的,合数:是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。)
    static int[] coms = new int[N + 1];
    //埃式筛法
    public static void ai(int n) {
        int sqt = (int) Math.sqrt(n);
        //这里我们来缩减范围到根号开始去找寻所有的合数
        for (int i = 2; i <= sqt + 1; i ++ ) {
            //若是当前是质数,则找出该质数的倍乘合数
            if (coms[i] == 0) {
                //最大范围应当我们要找的合数值
                for (int j = i * i; j <= n; j += i) coms[j] = 1;
            }
        }
    }
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        int count = 0;
        //进行埃式筛选
        ai(N);
        //判断质数
        for (int i = 2; i <= N; i++) {
            //为1的表示合数,对应0即为质数
            if (coms[i] == 0) count++;
        }
        System.out.println(count);
        long endTime = System.currentTimeMillis();
        System.out.println("执行时间:" + (float) (endTime - startTime) / 1000 + "s");
    }
}

欧拉筛法(线性筛选,O(n))
算法思想:在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
实际上在埃式筛法中找寻合数时,对于某个数会有多次重复找到例如:
i = 2时,会找出4 7 8 16 ... n
i = 3时,则会找到6 9 12
如何来解决这种多次重复找的情况呢?此时就可以使用欧拉筛法,实际上就是埃式筛法的升级版。
在欧拉筛法中我们添加一个primes数组来记录质数,对于倍乘是针对于这个primes来围绕找新的质数的,并且一旦当前数能够整除primes数组中的值时,那么找合数环节就直接结束了!虽然说是两重循环,但是它的时间复杂度是线性的。
代码:
复杂度分析:时间复杂度O(n)
package com.changlu.java;
class Main {
    static int N = (int) 1e6;
    //筛选出所有的合数(为1的,合数:是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。)
    static int[] coms = new int[N + 1];
    //记录所有的质数
    static int[] primes = new int[N + 1];
    //统计质数的个数
    static int ps_pos = 0;
    //欧拉筛:可筛选出所有质数以及每个数最小的质因数
    //时间复杂度O(n)
    public static void ola(int n ) {
        //遍历所有的数情况
        for (int i = 2; i <= n; i ++ ) {
            //记录质数
            if (coms[i] == 0) primes[ps_pos++] = i;
            //依据现有的质数来去求得倍乘质数(解决埃拉筛选中重复的问题)
            //遍历质数数组primes所有项,来进行求得对应当前数i能够构成的质数
            for (int j = 0; primes[j] * i <= n && j < ps_pos; j++) {
                //设置合数
                coms[primes[j] * i] = 1;
                //如果说当前的i能够整除拥有的质数,那么直接结束(核心)
                if (i % primes[j] == 0) break;
            }
        }
    }
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        int count = 0;
        //进行欧拉筛选
        ola(N);
        //遍历质数的个数
        System.out.println(ps_pos);
        long endTime = System.currentTimeMillis();
        System.out.println("执行时间:" + (double) (endTime - startTime) / 1000 + "s");
    }
}

参考文章
[1]. 【C++算法】20分钟学会高效地素数筛法,埃氏筛法,欧拉筛法:视频讲解
[2]. 欧拉筛法(线性筛)的学习理解
[3]. 线性筛(欧拉筛)——算法解析












![[标准库]STM32F103R8T6 串口的收发](https://img-blog.csdnimg.cn/cf35635de1df4f54a2b914f2c95666ff.png)






