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

相关文章

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

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

Verybot之OpenCV应用二:霍夫变换查找圆

其实我是想通过这个程序来测试一下,OpenCV在Verybot上跑得怎么样,霍夫变换的原理就不多说了,下面是程序: #include "cv.h"#include "highgui.h"#include "stdio.h"int main(int argc, char** argv){cvNamedWindow("vedio",0);CvCapture* capture;i

Win8下如何快速查找和删除电脑中的病毒

Win8系统如何查找和删除病毒?检查你的电脑是否存在病毒的一种快速方法是使用 Windows Defender. 此恶意软件防护随 Windows 提供,可帮助识别和删除病毒、间谍软件和其他恶意软件。   注意:如果你使用的是 Windows RT,则 Windows Defender 会始终启用,并且不能关闭。   如果你使用的是 Windows 8,则可以根据自己的喜好运行由其他

nyoj 685 查找字符串

当初一开始没做出来。 后来,学习过一段时间之后,在返回来做这道题,忽然发现,map类容器可以做。 PS:需要注意的是:此题如果用c++的输入输出的话,会超时。 O(time):gets()<  scanf() < cin。   附上代码: #include<stdio.h>#include<map>#include<string>#include<string.h>usin

【C++二分查找】2439. 最小化数组中的最大值

本文涉及的基础知识点 C++二分查找 LeetCode2439. 最小化数组中的最大值 给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。 每一步操作中,你需要: 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0 。 将 nums[i] 减 1 。 将 nums[i - 1] 加 1 。 你可以对数组执行 任意 次上述操作,请你返回可以得到的 n

七、Maven继承和聚合关系、及Maven的仓库及查找顺序

1.继承   2.聚合   3.Maven的仓库及查找顺序

notepad++ 正则表达式多条件查找替换

基础语法参考: https://www.cnblogs.com/winstonet/p/10635043.html https://www.linuxidc.com/Linux/2019-05/158701.htm   通常情况下我们查找的内容和要被替换掉的内容是一样的,我们只需要使用正则表达式精确框定查找内容,替换直接输入要替换的内容即可。 但有时会比较复杂,查找的内容,只需要替换其中

【中等】保研/考研408机试-二分查找(模板题)

二分查找就是在一个有序数组中查找某个值,以首端尾端的中点mid查找对比,mid与要查找的数进行对比,看落在哪个区间,在那个区间重新得到首端和尾端,进而得到新的mid值。 一、模板题 二分查找-I_牛客题霸_牛客网 class Solution {public:int search(vector<int>& nums, int target) {int left=0,right=nums.s

vite是如何实现依赖预构建的,浏览器为什么没有实现从node_modules查找依赖,vite开发环境解决了什么问题

浏览器的esmodule 为什么没有做从node_modules查找依赖项 浏览器是基于http请求的,node_modules中依赖项不可控,可能又会依赖很多的包,整个依赖图都需要加载的话很耗性能。 commonjs是运行在服务端的,以file形式读取文件,内部有规避机制。 依赖预构建 首先vite会找到对应的依赖,然后调用esbuild(对js语法进行处理的一个库),将其他规范的代码转换

【AngularJS】字符查找

首先,在页面的控制器代码中添加一个名为“key”的属性,用于保存用户在文本框中输入的字符内容,该属性初始化时为空值。         然后,通过“ng-repeat”指令显示数据时,调用Angular中的“filter”过滤器,并添加一个对象性字符参数,指定在数据对象的“name”属性中查找“key”值,即在“姓名”属性中查找文本框输入的字符,如果找到,则显示在列表中,否则不显示