不断优化的素数算法

前言:素数判断是算法中重要的一环,掌握优秀的素数判断方法是算法player的必修课。本文介绍的是由简到繁的素数算法,便于初学者从入门到精通。


素数(质数):只能被 1 和它本身整除的数称作素数,如:2、3、5、7、11等

目录

  • 一、🍓 暴力算法 🍓
  • 二、🍉 埃氏筛法 🍉
  • 三、🍈 欧拉筛法 🍈

一、🍓 暴力算法 🍓

  暴力算法是利用循环,看 2 − n 2 -n 2n 之间是否有能被 n n n 整除的数,若有,则 n n n 就是素数,否则就不是。
  Java代码如下: 时间复杂度为 O ( n ) O(n) O(n)

	/*** 不停地判断 2 ~ n-1 之间是否有数可以被 n 整除* @param n 输入的数字* @return 返回true为素数,false不为素数*/public static boolean isPrime(int n){for (int i= 2; i < n; i ++){//只要有数能被 n 整除,就返回falseif(n % i == 0)return false;}//没有数能被 n 整除就返回truereturn true;}

简单优化:
  其实循环的范围可以缩小到 n 的平方根,这是数学定理,就不过多赘述,这样时间复杂度就减小到了 O ( n ) O(\sqrt{n}) O(n ) ,那么代码就改变为如下:

	/*** 不停地判断 2 ~ 根号 n 之间是否有数可以被 n 整除* @param n 输入的数字* @return 返回true为素数,false不为素数*/public static boolean isPrime(int n){//Math.sqrt()的作用是求平方根for (int i= 2; i <= Math.sqrt(n); i ++){//只要有数能被 n 整除,就返回falseif(n % i == 0)return false;}//没有数能被n整除就返回truereturn true;}

小结: 暴力算法只适合单个或少量的素数判断,若判断某个范围之间有哪些素数,时间复杂度可能会达到 O ( n n ) O(n \sqrt{n} ) O(nn ) ,如下代码就会达到。

	//求 n 以内的所有素数for (int i = 2; i <= n; i++){if(isPrime(i))System.out.println(i);}

另外还有简单优化的方法,如:跳过偶数(2除外)的判断等就不再讲述

二、🍉 埃氏筛法 🍉

  埃氏筛法是求 n 以内所有素数的方法,把不大于根号 n 的所有素数的倍数剔除,剩下的就是素数。方法及例子如下:

求 20 以内的所有素数:

  1. 列出 2 以后的所有序列:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  2. 标记数列的第一个数为素数:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  3. 划掉被标记的数的所有倍数:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
    2 3 5 7 9 11 13 15 17 19
  4. 标记剩下数列中当前标记的下一个数为素数,再次重复执行以上操作,最后标记的数应为 n \sqrt{n} n (向下取整):
    2 3 5 7 9 11 13 15 17 19   标记 3
    2 3 5 7 9 11 13 15 17 19   删除 3 的倍数
    2 3 5 7 11 13 17 19      得到新的数列
    2 3 5 7 11 13 17 19      下一个数 5 大于了 n \sqrt{n} n ,就不用再标记了,当前数列已是结果
  5. 最后剩下的数都是 n 以内的素数:
    2 3 5 7 11 13 17 19

说明:在暴力算法那里我们提到,判断素数只需要判断到是否能被 n \sqrt{n} n 整除即可,所以在埃氏算法中,我们只需要标记到 n \sqrt{n} n ,就能把所有非素数剔除

图解:我们可以借助一个 int 型数组,当前单元的值为 1 表示当前下标的数是素数,否则不是素数,我们是借助 0 来完成上面第三步的划掉倍数的操作。上面的例子最终得到的数组如下:
在这里插入图片描述

该图就表示:2 3 5 7 11 13 17 19 都是素数,其他都不是。虽然 0 和 1 下标上的元素也是 1,但我们可以控制下标从 2 开始,毕竟 2 是第一个素数

Java代码实现:

	/*** 埃氏筛法* @param n 要求的是 n 以内的素数* @return 返回 int 型数组,0 表示当前下标数字不是素数,1 则就是素数*/public static int[] sieve(int n){int[] arr = new int[n+1];// +1是为了让下标范围是 0 ~ n//让数组元素都为 1,即初始都为素数for (int i = 0; i <= n; i++)arr[i] = 1;//从 2 开始,若为素数就标记,并标记它的倍数不是素数for (int i = 2;i <= Math.sqrt(n); i++){//只需要标记到根号 n 即可if (arr[i] == 1){//素数才标记,因为当前位置可能是被标记的 0//j += i 控制 i 的倍数都被标记 0for (int j = 2 * i;j <= n;j += i){arr[j] = 0;}}}return arr;}

小结:埃氏筛法的时间复杂度为 O ( n ∗ l o g n ) O(n*log n) O(nlogn),相对于暴力算法有了优化,适用于 10 6 以内范围的数据处理。常见的应用有:n 以内范围的素数求总和区间内的素数

三、🍈 欧拉筛法 🍈

  欧拉筛法是埃氏筛法的升级版。在埃氏筛法中,很多数都会被标记多次不是素数,例如 10 会在标记素数 2 、5 的时候都被标记不是素数,欧拉筛法则让每个数只被标记一次不是素数。使自身的时间复杂度达到线性的 O ( n ) O(n) O(n)。算法及例子如下,具体概念及证明就不在本文阐述,有兴趣的小伙伴可以去搜一下:

求 20 以内的所有素数:红色表示素数蓝色表示不是素数

  1. 列出 2 以后的所有序列,初始都标记为素数:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  2. 依次判断数列的每一个数,若为素数,则将其存放在一个数组中:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  3. 依次标记当前数的所有已找到素数倍的数不是素数:(当前所有已找到素数只有 2,当前数为 2,那么标记 2 * 2 = 4 不是素数)
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  4. 标记一次,就判断当前数是否是当前素数的倍数,是则停止标记非素数,进入到下一个数的判断(这是使每个数只被标记一次的关键)
  5. 重复以上操作,直到判断到最后一个数(20):
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  当前数为 3,是素数,先加入素数数组,当前素数有 2,3,则标记 6 和 9 不是素数
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  当前数为 4,不是素数,不加入数组,当前素数有 2,3,则标记 8 不是素数,因为4是2的倍数,就结束标记(否则会重复标记12),对应第4步,进入下一个数
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  当前数为 5,是素数,先加入数组,当前素数有 2,3,5,则标记 10 15 不是素数(25大于20,不用标记)
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  当前数为 6,不是素数,不加入数组,当前素数有 2,3,5,则标记 12 不是素数,因为 12 是 2 的倍数,就结束标记(可以看到前面阻止了对 12 的标记,避免和这里发生重复),进入下一个数
    后续操作与同理,最后会发现每个数只被标记了一次。最终的数如下:
    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

说明:通过以上步骤可以得出,需要两个数组,一个存已找到的素数,一个标记各个数是否为素数的数组

Java代码实现:

	/*** 欧拉筛法求 n 以内的所有素数* @param isPrime 标记是否为素数的数组,1表示是素数,0则不是* @param prime 存放以求得的素数的数组* @param n 就是 n 本身* @return 返回一共有几个素数*/public static int euler(int[] isPrime,int[] prime,int n){int cnt = 0;    //记录素数个数//让所有数组元素都为 1,即初始都为素数for (int i = 0;i <= n;i++)isPrime[i] = 1;//从 2 开始,若为素数就标记,并标记当前数的所有已找到素数倍的数不是素数for (int i = 2; i <= n; i++){//当前数为素数,则加入素数数组,并使 cnt计数加一if (isPrime[i] == 1) prime[++cnt] = i;//标记当前数的所有已找到素数倍的数不是素数for (int j = 1;j <= cnt && i * prime[j] <= n; j++){int k = i * prime[j];isPrime[k] = 0;//判断当前数是否是当前素数的倍数,是则停止标记非素数,进入到下一个数的判断//这里是使复杂度降低在线性的关键if (i % prime[j] == 0) break;}}return cnt;}

小结:欧拉筛将复杂度降低到线性,较于其他两种算法有了非常大的提升,但是远不及埃氏筛法容易理解,需要细细品味。但是算法嘛,很多时候都是先背板子,再刷题理解去掌握的,多用就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

总结二:linux面经

文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改&#xff1f;3、说说常用的Linux命令&#xff1f;4、说说如何以root权限运行某个程序&#xff1f;5、 说说软链接和硬链接的区别&#xff1f;6、说说静态库和动态…

(四)正点原子STM32MP135移植——u-boot移植

一、概述 u-boot概述就不概述了&#xff0c;u-boot、kernel、dtb三件套&#xff0c;dddd 经过国庆艰苦奋战&#xff0c;已经成功把所有功能移植好了 二、编译官方代码 进入u-boot的目录 2.1 解压源码、打补丁 /* 解压源码 */ tar xf u-boot-stm32mp-v2022.10-stm32mp-r1-r0.…

充分理清限制与条件+构造二分图+最小割:ARC142E

https://www.luogu.com.cn/problem/AT_arc142_e 他的充要条件是是什么&#xff1a; a i , a j ≥ m i n ( b i , b j ) a_i,a_j\ge min(b_i,b_j) ai​,aj​≥min(bi​,bj​)存在 a i ≥ m a x ( b i , b j ) a_i\ge max(b_i,b_j) ai​≥max(bi​,bj​) 第一个条件直接预处理一…

Springcloud支付模块

客户端消费者80 order 微服务提供者8001 payment 订单模块可以调动支付模块 步骤&#xff1a; 1、建moudle 2、改写pom 3、写yml 4、主启类 5、业务类

【LinuxC】时间、时区,相关命令、函数

文章目录 一、序1.1 时间和时区1.11 时间1.12 时区 1.2 查看时间时区的命令1.21 Windows1.22 Linux 二、C语言函数2.1 通用2.11 函数简介2.12 数据类型简介 2.2 windows 和 Linux特有函数2.3 C语言示例 一、序 1.1 时间和时区 1.11 时间 时间是一种用来描述物体运动变化的量…

黑马点评-01基于Redis实现短信登陆的功能

环境准备 当前模型 nginx服务器的作用 手机或者app端向nginx服务器发起请求,nginx基于七层模型走的是HTTP协议,可以实现基于Lua直接绕开tomcat访问Redis nginx也可以作为静态资源服务器,轻松扛下上万并发并负载均衡到下游的tomcat服务器,利用集群支撑起整个项目 使用nginx部…

黑马JVM总结(二十七)

&#xff08;1&#xff09;synchronized代码块 synchronized代码块的底层原理&#xff0c;它是给一个对象进行一个加锁操作&#xff0c;它是如何保证如果你出现了synchronized代码块中出现了问题&#xff0c;它需要给这个对象有一个正确的解锁操作呢&#xff0c;加锁解锁是成对…

【c++_containers】10分钟带你学会list

前言 链表作为一个像是用“链子”链接起来的容器&#xff0c;在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用&#xff0c;但是当他可以结合其他结构&#xff0c;比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。 言归正传&#xff0c;让…

overleaf在线编辑工具使用教程

文章目录 1 用 orcid注册overleaf获取模板2 使用模板 1 用 orcid注册overleaf获取模板 通常来说&#xff0c;在期刊投稿网站information for author中找template 。下载压缩包后上传到over leaf中。 加入找不到官方模板&#xff0c;用overleaf中的 2 使用模板 .bib文件&…

3D孪生场景SDK:Viwer 孪生世界

NSDT 编辑器 提供三维场景构建、场景效果设计、场景服务发布全流程工具等&#xff0c;其场景编辑器支持资产管理、灯光设置、骨骼动画等功能&#xff1b;致力于协助资源不足的中小企业及个人快速开发数字孪生场景&#xff0c;帮助企业提高生产力、实现降本增效。 NSDT编辑器简…

adb详细教程(四)-使用adb启动应用、关闭应用、清空应用数据、获取设备已安装应用列表

adb对于安卓移动端来说&#xff0c;是个非常重要的调试工具。本篇介绍常用的adb指令 文章目录 一、启动应用&#xff1a;adb shell am start二、使用浏览器打开指定网址&#xff1a;adb shell am start三、杀死应用进程adb shell am force-stop/adb shell am kill四、删除应用所…

【AI视野·今日CV 计算机视觉论文速览 第262期】Fri, 6 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Fri, 6 Oct 2023 Totally 73 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Improved Baselines with Visual Instruction Tuning Authors Haotian Liu, Chunyuan Li, Yuheng Li, Yong Jae Lee大型多模…

python开发幸运水果抽奖大转盘

概述 当我女朋友跟我说要吃水果&#xff0c;又不知道吃啥水果时候&#xff0c;她以为难为到我了&#xff0c;有啥事难为到程序员的呢&#xff01; 今天用python利用第三方tkinterthreadingtime库开发一个幸运水果抽奖大转盘&#xff01;抽到啥吃啥 详细 老规矩&#xff01;咱…

基于A4988/DRV8825的四路步进电机驱动器

概述 简化板的CNC sheild V3.0&#xff0c;仅保留步进电机速度与方向的控制引脚STEP/DIR、使能端EN、芯片供电VCC\GND&#xff0c;共计11个引脚。PCB四周开设四个M3通孔&#xff0c;以便于安装固定。此外&#xff0c;将板载的焊死的保险丝更改为可更换的保险座保险丝&#xff…

Labview 实战 99乘法表

基于新手小白&#xff0c;使用Labview实现99乘法表&#xff0c;敢于发表自己的一点方法&#xff0c;还请各位大侠放过&#xff01; 如下&#xff1a; 运行效果如下&#xff1a; 思路为&#xff1a;将要显示出来的数据&#xff0c;全部转换为字符串形式&#xff0c;再塞入到数组…

Java基于SSM+Vue的平时成绩管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

频次直方图、KDE和密度图

Seaborn的主要思想是用高级命令为统计数据探索和统计模型拟合创建各种图形&#xff0c;下面将介绍一些Seaborn中的数据集和图形类型。 虽然所有这些图形都可以用Matplotlib命令实现&#xff08;其实Matplotlib就是Seaborn的底层&#xff09;&#xff0c;但是用 Seaborn API会更…

基于SSM+Vue的鲜花销售系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Kafka快速实战以及基本原理详解

这一部分主要是接触 Kafka &#xff0c;并熟悉 Kafka 的使用方式。快速熟练的搭建 kafka 服务&#xff0c;对于快速验证一些基于Kafka 的解决方案&#xff0c;也是非常有用的。 一、 Kafka 介绍 ChatGPT 对于 Apache Kafka 的介绍&#xff1a; 1 、 MQ 的作用 MQ &#xff1a;…

【AI视野·今日NLP 自然语言处理论文速览 四十九期】Fri, 6 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Fri, 6 Oct 2023 Totally 44 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers MathCoder: Seamless Code Integration in LLMs for Enhanced Mathematical Reasoning Authors Ke Wang, Houxi…