筛选质数的三个方法:1.素数判断,2埃氏法,3欧拉法。

文章目录

前言

一、素数是什么?

二、算法使用原理

1.合数:合数除了1和它本身以外,还有其他因数。与素数相对,素数只有1和它本身两个因数,而合数则至少有三个因数。

2.我们理解了合数的概念后,可以知道一个合数可以由至少三个因数构成如,6=1*2*3,说明所有素数的倍数都可以是合数,那么我们用到的埃氏筛就是利用这个原理将所有合数标记。

三,埃氏筛

一、定义与背景

二、核心原理

三、算法优势与不足

四、结论

2.代码展示

四,欧拉筛

欧拉筛法选素数的核心思想

欧拉筛法在埃氏筛法上的优化

总结

题目展示:来自力扣的3233题​

思路

代码

写法二


 


前言

在进行计算机编程题的练习的时候,大家多少都会遇到素数判断的问题。那么这篇文章将告诉大家判断素数的方法和一些计数的技巧,以及一些其他的关于求素数题目,和优化代码中的一些地方,制作不易求个免费赞。

一、素数是什么?

素数(Prime number),又称质数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。换句话说,一个大于1的自然数,如果只能被1和它本身整除,那么这个数就是素数。例如,2、3、5、7、11等都是素数,因为它们都只能被1和它们自己整除。而4、6、8、9等则不是素数,因为它们除了1和自身外,还能被其他自然数整除。

素数在数论中扮演着非常重要的角色,许多数学定理和猜想都与素数有关。例如,著名的哥德巴赫猜想就断言每一个大于2的偶数都可以写成两个素数之和。此外,素数也是加密技术中广泛使用的数学工具,如RSA加密算法就依赖于大素数的生成和分解的困难性。

二、算法使用原理

1.合数:合数除了1和它本身以外,还有其他因数。与素数相对,素数只有1和它本身两个因数,而合数则至少有三个因数。

2.我们理解了合数的概念后,可以知道一个合数可以由至少三个因数构成如,6=1*2*3,说明所有素数的倍数都可以是合数,那么我们用到的埃氏筛就是利用这个原理将所有合数标记。

三,埃氏筛

埃氏法筛选素数的核心原理可以归纳为以下几点:

一、定义与背景

埃拉托斯特尼筛法(Sieve of Eratosthenes),简称埃氏筛法,是一种简单且年代久远的筛法,用来找出一定范围内所有的素数。该算法由古希腊数学家埃拉托斯特尼提出,是一种基于素数的性质进行筛选的算法。

二、核心原理

  1. 初始化:首先,将待在的素数,通常使用一个布尔数组来表示,数组的下标对应自然数,数组的值表示该下标对应的筛选范围内的所有数都视为潜数是否为素数(true表示是素数,false表示不是素数)。

  2. 筛选过程

    • 从最小的素数2开始,将其所有的倍数(除了2本身)都标记为非素数(即将对应数组位置的值设为false)。这是因为素数的定义是只能被1和自身整除的数,所以任何素数的倍数都不可能是素数。
    • 接着,找到下一个未被标记为非素数的数(即下一个素数),重复上述过程,继续标记其所有倍数为非素数。
    • 这个过程一直持续,直到遍历完所有待筛选的数或者当前素数的平方大于待筛选范围的最大值时停止。因为如果一个合数n有除了1和它本身以外的因数,那么这些因数中必然有一个不大于sqrt(n)(算术基本定理)。所以,当一个素数的平方大于待筛选范围的最大值时,就可以确定剩下的数都是素数了。
  3. 结果输出:最后,未被标记为非素数的数就是素数,可以通过遍历布尔数组来输出这些素数。

三、算法优势与不足

优势

  • 相对于其他简单的素数筛选方法(如试除法),埃氏筛法能够更快速地找出一定范围内的所有素数。
  • 算法实现简单,易于理解和编程。

不足

  • 当筛选范围较大时,虽然算法的时间复杂度相对较低(接近O(nloglogn)),但空间复杂度较高,需要额外的空间来存储每个数的状态。
  • 算法在筛选过程中可能会重复标记某些数为非素数(例如,一个数可能会同时被多个素数的倍数所标记),这虽然不影响最终结果的正确性,但会增加一些不必要的计算量。

四、结论

埃氏筛法是一种简单有效的素数筛选方法,其核心原理在于利用素数的性质来逐步排除非素数,从而得到所有素数。尽管该方法在筛选范围和空间使用上存在一定的限制,但在实际应用中仍然具有广泛的用途和价值。

2.代码展示

其中的  j=i*2;可以改成i*i因为写法不一样,原因是因为1*2*3和1*3*2的答案是一样的,所以用i*2会造成重复,但是影响不大,注意方便理解。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	  int n;
	  cin>>n;/范围2-n;
	  int prime[n+1]={0};标记数组,可以用bool prime[n+1];
	  int ans=0;
	  for(int i=2;i<=n;i++)
	  {
	  	if(!prime[i])//如果是素数
	  	{
	  		for(int j=i*2;j<=n;j=j+i)//素数的倍数都是合数,原因在开始介绍了。为什么是j=j+i因为是倍数增加。注意改变的是j不是i。i相当于素数i*2就是一倍。
	  		{
	  		prime[j]=1;//对合数进行标记。
			}
		  }
	  }
	  for(int i=2;i<=n;i++)//遍历,没有标记的就说素数
	  {
	  	if(prime[i]==0) ans++;
	  }
	  cout<<ans;
	  return 0;
}



//优化版; 对答案的储存进行的了优化,利用了前缀合。
#include<bits/stdc++.h>
using namespace std;
int main()
{
	  int n;
	  cin>>n;
	  int prime[n+1]={0};//标记 
	  int sum[n+1]={0};
	  int ans=0;
	  for(int i=2;i<=n;i++)
	  {
	  	if(!prime[i])//如果是素数
	  	{
	  		sum[i]=sum[i-1]+1;//前缀和求当前位置的素数有多少个 
	  		for(int j=i*2;j<=n;j=j+i)//核心 标记合数 如12=2*2*3;12=2*6;<=n表面不超过最大范围 
	  		{					//成倍增加 
	  			prime[j]=1;
			}
		  }
		  else
		  {
		  	sum[i]=sum[i-1];//如果不是素数继承前面的状态。 
		  }
	  }
	  cout<<sum[n];
	  return 0;
}

四,欧拉筛

面对埃氏法的不足,我们又衍生出一种优化的算法欧拉筛。

欧拉筛法(Euler's Sieve)和埃氏筛法(Sieve of Eratosthenes)都是用于在给定范围内快速筛选出所有质数的算法。欧拉筛法作为埃氏筛法的优化版本,在效率上有了显著提升。以下是欧拉筛法选素数的核心思想以及在埃氏筛法上的优化点:

欧拉筛法选素数的核心思想

欧拉筛法的核心思想在于确保,从而避免了重复筛选,提高了算法的效率。具体来说,当遍每个合数只被其最小的质因子筛掉一次历到一个数i时,欧拉筛法会使用小于等于i的所有已知质数prime[j]去筛i*prime[j](其中j从0开始,且prime[j]≤sqrt(i)),但这里有一个关键优化:当i能被prime[j]整除时(即i%prime[j]==0),就停止用更大的质数去筛i的倍数。这是因为如果继续用更大的质数筛,那么筛掉的将是i的倍数与更大质数的乘积,而这个乘积的最小质因子仍然是prime[j],这会导致重复筛选(下面避免重复筛选解释了)。注意储存素数的数组是递增的,所有要从头遍历,才能保证被最小质因数筛掉。

欧拉筛法在埃氏筛法上的优化

  1. 避免重复筛选
    • 埃氏筛法中,一个合数可能会被它的多个质因子重复筛选多次(例如,30=2*15=3*10=5*6,在埃氏筛法中,30会被2、3、5都筛一遍)。而欧拉筛法通过确保每个合数只被其最小的质因子筛掉一次,从而避免了这种重复筛选。(解决方法就是开了一个数组储存素数)
  2. 时间复杂度降低
    • 埃氏筛法的时间复杂度为O(nloglogn),而欧拉筛法由于避免了重复筛选,其时间复杂度接近O(n),是一种非常高效的质数筛选算法。
  3. 实现方式
    • 欧拉筛法通常采用两个数组:一个用于存储质数(prime数组),另一个用于标记一个数是否已经被筛掉(vis数组或类似的标记方式)。遍历从2到n的所有数,对于每个数i,如果它还未被筛掉(即是质数),则将其加入到prime数组中,并用prime数组中的每个质数去筛 i 的倍数,但遵循上述的关键优化。
  4. 代码
    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
    	  int n;
    	  cin>>n;
    	  int prime[n+1]={0};
    	  int sum[n+1]={0}; 
    	  int ans=0;
    	  for(int i=2;i<=n;i++)
    	  {
    	  	if(!sum[i]) prime[ans++]=i;//储存素数的数组。
    	  		for(int j=0;j<ans;j++)
                这里用素数数组的总数是因为我们调用的是下标
    	  		{
    	  			if(prime[j]*i>n) break;
    	  			sum[prime[j]*i]=1;
                       //这一步的解释,这里的i表示的不是素数,还是利用合数=1*x*y
                       //埃氏法是固定素数x,遍历y,而欧拉筛是固定y,就是这里的i,遍历素数数组,这 
                         就是我们为什么要存放素数
    	  			if(i%prime[j]==0) break;//判断是否能被最小质因数整除;
                    避免重复筛选,文章内有解释。
    			}
    	}
    	  cout<<ans;
    	  return 0;
    }

总结

欧拉筛法通过避免重复筛选,在埃氏筛法的基础上实现了时间复杂度的显著降低,是一种高效且实用的质数筛选算法。其核心思想在于确保每个合数只被其最小的质因子筛掉一次,从而提高了算法的效率。在实际应用中,欧拉筛法在处理大规模数据时表现出色,被广泛应用于密码学、数论、组合数学等领域。

题目展示:来自力扣的3233题

思路

根据题意,文章让我们找特殊数字,这个数字有三个因数,那么什么数只有有三个因数呢,肯定是质数的平方了,所有题目的真正意思是让我们找这个范围内质数的平方,如何简便运算呢,首先让我们找平方,那么可以先缩小范围,找可以开根号的数里面的质数,第一步就可以对范围进行预处理,然后套我们的素数筛选方法。

代码

写法二

喜欢偷懒。其实就是换欧拉筛法,主体都是一样的,优化版本也是,靠各位编程之星自己解决了,留点思考量。

感谢点赞收藏。

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

关于不上作者榜就原神启动那件事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值