欧拉筛法(线性筛)的学习理解

前言在刚接触编程语言时,对于寻找素数,第一时间想到的便是二重循环暴力查找,其复杂度O(n),通过循环中只判断到根号n可以优化一些,不过复杂度也达不到预期。在数论的学习中,我学到了埃氏筛法,O(nloglogn)的算法,而在一些数据范围达到1e7这样的题目中,也很难让人满意,于是我便学习了欧拉筛法,也即O(n)的线性筛法。埃氏筛法埃氏筛法的基本思想:从2开始,将每个质数的倍数都…

大家好,又见面了,我是你们的朋友全栈君。

前言

在刚接触编程语言时,对于寻找素数,第一时间想到的便是二重循环暴力查找,其复杂度O(n^2),通过循环中只判断到根号n可以优化一些,不过复杂度也达不到预期。在数论的学习中,我学到了埃氏筛法,O(nloglogn)的算法,而在一些数据范围达到1e7这样的题目中,也很难让人满意,于是我便学习了欧拉筛法,也即 O(n)的线性筛法。

埃氏筛法

  • 埃氏筛法的基本思想 :从2开始,将每个质数的倍数都标记成合数,以达到筛选素数的目的。
  • 代码 :
int visit[maxn];  
void Prime(){
    mem(visit,0);           //初始化都是素数
    visit[0] = visit[1] = 1;  //0 和 1不是素数
    for (int i = 2; i <= maxn; i++) {
        if (!visit[i]) {         //如果i是素数,让i的所有倍数都不是素数
            for (int j = i*i; j <= maxn; j += i) { 
                visit[j] = 1;
            }
        }
    }

这里有一个小优化,j 从 i * i 而不是从 i + i开始,因为 i*(2~ i-1)在 2~i-1时都已经被筛去,所以从i * i开始。

  • 埃氏筛法的缺陷 :对于一个合数,有可能被筛多次。例如 30 = 2 * 15 = 3 * 10 = 5*6……那么如何确保每个合数只被筛选一次呢?我们只要用它的最小质因子来筛选即可,这便是欧拉筛法。

欧拉筛法

  • 欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
  • 代码 :
int prime[maxn];
int visit[maxn];
void Prime(){
    mem(visit,0);
    mem(prime, 0);
    for (int i = 2;i <= maxn; i++) {
        cout<<" i = "<<i<<endl;
        if (!visit[i]) {
            prime[++prime[0]] = i;      //纪录素数, 这个prime[0] 相当于 cnt,用来计数
        }
        for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
//            cout<<"  j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
            visit[i*prime[j]] = 1;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
}
  1. 对于visit[i*prime[j]] = 1 的解释: 这里不是用i的倍数来消去合数,而是把 prime里面纪录的素数,升序来当做要消去合数的最小素因子。
    打表观察来理解 :
    输出前十个循环
    发现i在消去合数中的作用是当做倍数的。
  2. 对于 i%prime[j] == 0 就break的解释 :当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
    举个例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。

结语

对于欧拉筛法的学习是先从接触到题开始的,研究了一天才弄懂,很惭愧,再次遇到题也不见得可以游刃有余的解决,在此与大家共勉,学海无涯。
附上题目 :https://nanti.jisuanke.com/t/30999 (大佬眼中的签到题)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125441.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)


相关推荐

  • Redis 序列化时报错Could not read JSON: Cannot construct instance of …

    Redis 序列化时报错Could not read JSON: Cannot construct instance of …

  • IDEA版本的Mybatis逆向工程使用攻略「建议收藏」

    IDEA版本的Mybatis逆向工程使用攻略「建议收藏」idea版本的Mybatis逆向工程开发(自动生成实体类层,mapper文件,dao层)一、使用逆向工程开发概述今天早上打算做一个spring+springmvc+mybatis的项目,然后感觉这个mapper文件太难写了,最后就想在网上找一个方法能解决不写mapper文件的方法,最后就发现了这个懒人必背法宝:“myabtis逆向工程”的技术,但是全网几乎都是“eclipse版本生成MyBatis逆向工程”,然后自己就搞了一个idea+maven版本的逆向工程,并且全部在gitee开源了的哟,如果

  • ettercap 局域网嗅探

    ettercap 局域网嗅探背景知识本次嗅探试验所使用到的工具有两个,ettercap和driftnet。ettercap是一款现有流行的网络抓包软件,他利用计算机在局域网内进行通信的ARP协议的缺陷进行攻击,在目标与服务器之间充当中间人,嗅探两者之间的数据流量,从中窃取用户的数据资料。ettercap的介绍ettercap有两种运行方式,UNIFIED和BRIDGED。UNIFIED的方式是以中间人方式嗅探,…

  • 详解布隆过滤器的原理、优缺点

    详解布隆过滤器的原理、优缺点什么是布隆过滤器?本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilisticdatastructure),特点是高效地插入和查询,可以用来告诉你“某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。HashMap的问题讲述布隆过滤器的原理之前,我们先思考一下,通常你判断某…

  • Python定义计算矩阵转置的函数

    Python定义计算矩阵转置的函数定义计算矩阵转置的函数1)使用循环进行转置matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]#打印矩阵defprintMatrix(m):foreleinm:foreinele:print(‘%3d’%e,end=”)print(”)…

  • matlab 循环矩阵_matlab循环输出数组

    matlab 循环矩阵_matlab循环输出数组MATLAB的矩阵求值的循环语句?clc;clearall;closeall;t0=[11];a=[12;34]t=t0;t(1,:)=t0’\an=10;fori=2:nt(i,:)=t(i-1,:)’\a;endtmatlab中的核矩阵for循环问题A(i,:)-A(j,:)表示A矩阵的第i行减去第j行,得到的是一个行向量;norm函数是取2范数,也就是向量的各项平方求和再开方.(因此我觉…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号