【算法】数论——筛质数(线性筛法)

题目

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

输入格式

共一行,包含整数 n。

输出格式

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

数据范围

1 ≤ n ≤ 10^6

思路

朴素筛法
做法 :把2~(n-1)中的所有的数的倍数都标记上,最后没有被标记的数就是质数.
原理 :假定有一个数p未被2~(p-1)中的数标记过,那么说明,不存在2~(p-1)中的任何一个数的倍数是p,也就是说p不是2~(p-1)中的任何数的倍数,也就是说2~(p-1)中不存在p的约数,因此,根据质数的定义可知:p是质数.
时间复杂度:约为O(nlogn);

埃氏筛(稍加优化版的筛法)
质数定理 :1~n中有n/lnn个质数.
原理 :在朴素筛法的过程中只用质数项去筛.
时间复杂度:粗略估计:O(n).实际:O(nlog(logn)).1~n中,只计算质数项的话,"1/2+1/3+1/4+1/5+...+1/n"的大小约为log(logn)。

线性筛法 核心 :1~n内的合数p只会被其最小质因子筛掉.
原理:1~n之内的任何一个合数一定会被筛掉,而且筛的时候只用最小质因子来筛,然后每一个数都只有一个最小质因子,因此每个数都只会被筛一次,因此线性筛法是线性的.

注意:

1、枚举到 i 的最小质因子的时候就会停下来,即" if(i%primesj==0) break ; "。

2、因为从小到大枚举的所有质数,所以当" i % primesj != 0 "时,primes j 一定小于 i 的最小质因子,而且 primesj 一定是primesj * i的最小质因子。

3、关于for循环的解释:

注:首先要把握住一个重点:我们枚举的时候是从小到大枚举的所有质数

(1)当i%primesj==0时,因为是从小到大枚举的所有质数,所以primesj就是i的最小质因子,而primesj又是其本身primesj的最小质因子,因此当i%primesj==0时,primesj是primesj * i的最小质因子。

(2)当 i%primesj!=0 时,因为是从小到大枚举的所有质数,且此时并没有出现过有质数满足i%primesj == 0,因此此时的primesj一定小于i的最小质因子,而primesj又是其本身primesj的最小质因子,所以当i%primesj!=0时,primesj也是primesj * i的最小质因子。

(3)综合1,2得知,在内层for循环里面无论何时,primesj都是primesj * i的最小质因子,因此 "stprimes\[j \* i = true"语句就是用primesji这个数的最小质因子来筛掉这个数。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int primes[N],cnt;
bool st[N];// 储存该值i是不是为非质数

void get_primes(int n)
{
    for(int i = 2;i <= n; i ++)// 依次判断2~n是否为质数
    {
        if(!st[i]) primes[cnt ++] = i;// 如果该数是质数则将其储存起来,如果不是质数则不储存
        for(int j = 0;primes[j] <= n / i; j ++)// 筛掉是i的primes[j]倍的所有合数
        {
            st[primes[j] * i] = true;// 确保每个合数是被他最小的质因子筛掉的
            if(i % primes[j] == 0) break;// primes[j]一定是i的最小质因子
            //p[j]一定是i的最小质因子,pj也一定是pj*i的最小质因子
        }
    }
}

int main()
{
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;
    return 0;
}
相关推荐
JieE2121 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2122 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack203 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树3 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2123 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2123 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术4 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦4 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
clint4564 天前
C++进阶(1)——前景提要
c++