1-n范围内的质数查找:埃拉托斯特尼筛法

2023-12-01 07:10

本文主要是介绍1-n范围内的质数查找:埃拉托斯特尼筛法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 质数查找思路
      • 质数定义
      • 代码思路
    • 写法
      • 重要逻辑:第一层for循环结束条件是i * i <= n而不是i<=n
      • 第二层循环如何筛查i所有倍数
    • 完整版:返回0-n正整数中所有质数
    • 时间复杂度
    • 例题
    • 参考资料:

质数查找思路

质数定义

质数是一个自然数,且除了1和它本身以外没有其他因数。换句话说,如果一个数大于1,且只有两个正因数(1和它本身),那么它就是一个质数。例如,2、3、5、7、11、13等都是质数。注意,1和0不是质数

根据质数的定义,质数p的倍数必然有其他因数(至少包括p本身),所以它们不可能是质数。因此,我们在使用埃拉托斯特尼筛法求质数时,对于每一个已知的质数p,都需要将所有p的倍数标记为非质数

例如,当p=2时,我们将所有2的倍数(即所有偶数)标记为非质数。然后,找到下一个还未被标记为非质数的数(即3),将所有3的倍数标记为非质数,以此类推。这样,剩下的未被标记的数就都是质数了。

在1–9范围内排查质数,遍历2和3的情况如图所示。

在这里插入图片描述

代码思路

代码方面的思路:

我们先定义一个is_prime数组 这个数组初始化为大小是n,初值全部是1

i从2到n开始遍历(因为0和1不是质数)。遇到不是质数的,就让对应的下标i的数值变成0,最后,得到的所有值是1的下标i就是n以内所有的质数

埃氏筛法是使用两层循环来判断0–N范围内的质数,第一层循环遍历小于等于n的所有数字,第二层循环对遍历到的数字,去除<=n范围内他们的所有倍数

写法

在1–n范围内,用埃拉托斯特尼筛法找出所有的质数的写法:

// 先设定一个数组,大小为n,初值全部为1
// 从2开始,对于每一个i,如果i是质数,那么i的所有倍数都不是质数
// 只需要检查到 sqrt(n) ,因为如果 n 不是质数,那么它必定有一个小于等于 sqrt(n) 的因子
for (int i = 2; i * i <= n; ++i) {if (is_prime[i]==1) {for (int j = i * 2; j <= n; j += i) {is_prime[j] = 0;}}
}

重要逻辑:第一层for循环结束条件是i * i <= n而不是i<=n

理论上来说,我们确实应该在第一层循环遍历所有数字。

但是,有一个基于数论的重要性质:如果一个数n不是质数那么它必然可以被某个小于等于sqrt(n)的数整除

某数字被x整除,就是指当前数字/x没有余数

例如,8不是一个质数,我们可以看到2和4是8的因数,2*4等于8,所以8可以被2和4整除。在这个例子中,sqrt(8)大约等于2.83,所以2是小于等于sqrt(8)的数,它可以整除8。实际上,对于任何非质数,我们总是可以找到至少一个小于等于它的平方根的因数

设想一下,如果一个数n不是质数,那么它至少有一对因数。设这对因数为a和b(a ≤ b)。如果a和b都大于sqrt(n)那么a * b将大于n,这与假设a和b是n的因数矛盾;同样,如果a和b都小于等于sqrt(n),那么a * b将小于n,也与假设矛盾。因此,对于n的任何一对因数,必然有一个小于等于sqrt(n),另一个大于等于sqrt(n)

因此,在埃拉托斯特尼筛法中,我们只需要检查到sqrt(n)就可以了

我们只需要将从2到sqrt(n)的所有数的倍数剔除就能得到所有的质数。这样也可以大大降低筛选质数的时间复杂度,使其在处理大规模数据时更高效。\

第二层循环如何筛查i所有倍数

筛所有倍数的逻辑:设定一个数字j,从j=i*2开始,每次循环j+=i,就是增加了一倍

for(int j=i*2;j<=n;j+=i)

通过这个逻辑寻找所有小于或等于n的i的倍数,然后将它们标记为非质数。

完整版:返回0-n正整数中所有质数

#include <vector>
#include <cmath>
using namespace std;//返回0--n正整数中所有的质数
vector<int>judgePrime(int n){//包括0,所以要定义n+1vector<int>isPrime = (n+1,1);vector<int>result;//0和1不是质数isPrime[0]=isPrime[1]=0;//搜索i到sqrt(n)for(int i=2;i*i<=n;i++){if(isPrime[i]==1){for(int j=i*2;j<=n;j+=i){isPrime[j]=0;}}}//result就是isPrime数组中所有值为1的下标for(int i=2;i<=n;i++){if(isPrime[i]==1){result.push_back(i);}}return result;}

时间复杂度

埃拉托斯特尼筛法的时间复杂度是O(n log log n)

这是因为在计算质数的时候,我们首先从2开始,然后找出2的所有倍数并将它们标记为非质数。然后,我们找到下一个仍然被标记为质数的数(在这个例子中是3),并找出3的所有倍数并将它们标记为非质数。我们继续这个过程,直到我们已经检查了所有小于等于sqrt(n)的数。由于每个数只被标记一次,所以总的操作次数是n/2+n/3+n/5+…这个级数的和近似为n log log n

例题

leetcode 6916.和等于目标的质数对2761. 和等于目标值的质数对 - 力扣(LeetCode)

给你一个整数 n 。如果两个整数 xy 满足下述条件,则认为二者形成一个质数对:

  • 1 <= x <= y <= n
  • x + y == n
  • xy 都是质数

请你以二维有序列表的形式返回符合题目要求的所有 [xi, yi] ,列表需要按 xi非递减顺序 排序。如果不存在符合要求的质数对,则返回一个空数组。

**注意:**质数是大于 1 的自然数,并且只有两个因子,即它本身和 1

示例 1:

输入:n = 10
输出:[[3,7],[5,5]]
解释:在这个例子中,存在满足条件的两个质数对。 
这两个质数对分别是 [3,7][5,5],按照题面描述中的方式排序后返回。

示例 2:

输入:n = 2
输出:[]
解释:可以证明不存在和为 2 的质数对,所以返回一个空数组。 

提示:

  • 1 <= n <= 10^6

解法:

class Solution {
public:vector<vector<int>> findPrimePairs(int n) {vector<vector<int>>result;vector<int>isPrime(n+1,1);isPrime[0]=0;isPrime[1]=0;//先调整i的数组,让数组里所有非质数下标对应的数值为0for(int i=2;i*i<=n;i++){if(isPrime[i]==1){for(int j=i*2;j<=n;j+=i){isPrime[j]=0;}}}//在n以内找质数对for(int i=2;i<=n/2;i++){if(isPrime[i]==1&&isPrime[n-i]==1){//当我们试图创建一个一维向量加入二维数组,必须要用{}而不是[]result.push_back({i,n-i});//把质数对加入结果}}return result;}
};

参考资料:

算法数学知识总结

这篇关于1-n范围内的质数查找:埃拉托斯特尼筛法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/440264

相关文章

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图

Python中高级文本模式匹配与查找技术指南

《Python中高级文本模式匹配与查找技术指南》文本处理是编程世界的永恒主题,而模式匹配则是文本处理的基石,本文将深度剖析PythonCookbook中的核心匹配技术,并结合实际工程案例展示其应用,希... 目录引言一、基础工具:字符串方法与序列匹配二、正则表达式:模式匹配的瑞士军刀2.1 re模块核心AP

基于Python实现数字限制在指定范围内的五种方式

《基于Python实现数字限制在指定范围内的五种方式》在编程中,数字范围限制是常见需求,无论是游戏开发中的角色属性值、金融计算中的利率调整,还是传感器数据处理中的异常值过滤,都需要将数字控制在合理范围... 目录引言一、基础条件判断法二、数学运算巧解法三、装饰器模式法四、自定义类封装法五、NumPy数组处理

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C#实现查找并删除PDF中的空白页面

《C#实现查找并删除PDF中的空白页面》PDF文件中的空白页并不少见,因为它们有可能是作者有意留下的,也有可能是在处理文档时不小心添加的,下面我们来看看如何使用Spire.PDFfor.NET通过C#... 目录安装 Spire.PDF for .NETC# 查找并删除 PDF 文档中的空白页C# 添加与删

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

使用Python合并 Excel单元格指定行列或单元格范围

《使用Python合并Excel单元格指定行列或单元格范围》合并Excel单元格是Excel数据处理和表格设计中的一项常用操作,本文将介绍如何通过Python合并Excel中的指定行列或单... 目录python Excel库安装Python合并Excel 中的指定行Python合并Excel 中的指定列P