每日一题——孪生素数对(教你如何高效判断素数,判断素数的全部方法)

学习目标:

每天睡前是否感到浑浑噩噩,一天又在不知不觉中过去,回想我今天都干了什么呢?

啊~我这一天又什么也没干,好有罪恶感啊,不行,我明天一定要好好学算法(手动狗头)。

明日复明日,明日何其多?不要等明天啦,和小编一起,每天睡前一道算法题,不仅解决你一天的空虚,更能助你安心入眠,远离熬夜。还能学到一点算法知识。不要小看这些知识哦,不积跬步无以至千里,不积小流无以成江海。每位大佬都不是一夜成名,都是从小白做起,日积月累,终成大佬,和小编一起,每日一题,走向大佬之路吧!


学习内容:

我们的题基本都是一些较为基础,适合日(睡)常(前)看的题,不会让你一眼就看出答案,是稍稍一点脚就能摸到头绪,但是在想的过程中又一时不知如何实现,再一想,又柳暗花明,最终跟着小编的思路一起解决问题,有不同思路可以发在评论区,一起讨论。“你若在,我必回”。


我们今天的题目是孪生素数对,首先,介绍一下什么是素数

简单来说,素数是只能被1和它本身整除的数。其中特例是:0和1既不是素数也不是合数,2是素数。

那么我们首先来思考,如何判断一个数n是不是素数。第一想法应该是一个循环,从2到 n-1进行判断,如果存在一个数能整除,则不是素数,反之则是素数。对吧,让我们看看代码。

int prime(int n){
	int i;
	for(i=2;i<n;i++){
		if(n%i==0){
			return 0;//不是素数 
		}
	}
	return 1;//是素数 
}

虽然这样是没错的,但是我们想一下,从2到n,是不是需要判断的太多了,会有很多没用的判断。那么如何减少没用的判断,就要先思考没用的判断从何而来,以36为例:它的因子有2,3,4,6,9,12,18,可以知道,它的因子一定是成对出现,而特殊的6,其实准确来说是6*6,也恰好是6,将这些成对出现的因子分成两半。说到这里,相信你一定发现了吧,我们的循环只需要判断到根号n,就能发现它的全部因子对。代码也只需要将判断条件改为根号n。

int t=sqrt(n);
for(i=2;i<=t;i++){
		if(n%i==0){
			return 0;//不是素数 
		}
	}

这里为了减少每次判断都需重新计算根号n,所以提前将他计算得到。


到此,我们所能想到的大概就是这些了,但是当n特别大的时候,即使是根号n,仍然会很大。那么还有没有什么更好的方法去优化它,当n=1000000时,开根得1000,还会有90,91,92,93等数字,我们明知道它们不可能时n的因子,但还是要进行无用的判断。所以,如何避免这些没用的判断呢?

如果你做过很多这样的题,见到过很多素数,你会发现这样的一个规律:素数一定是在6的倍数两侧出现,2,3除外。有关这个定理的证明,相信属性小编的朋友一定都知道,小编是一个实用主义者,交给你最干的干货,让你看完就能用,这个定理的证明不需要我们的掌握,所以就不加赘述。那么我们看看这个定理应该怎么用代码实现。

#include<stdio.h>
#include<math.h>
int prime(int n){
	if(n==2 && n==3) return 1;
	if(n%6==5 || n%6==1){
		int t=sqrt(n)+1,i;
		for(i=2;i<t;i++){
			if(n%i==0){
				return 0;
			}
		}
		return 1;
	}
	return 0;
}
int main() {
	int k;
	scanf("%d",&k);
	printf("%d\n",prime(k));//1是 0否
}

这个判断方法已经可以快速判断一个数是不是素数,但是还要经过进行多次判断。

人类的思维总是在不断追求完美的过程中逐渐提高,那么我们还能不能有更快的方法,让我们一次就能将判断结果得出。也就是O(1),看到这个复杂度,不知道你有没有想到桶排序?就是将每个数存放在数组中。

没错,那个方法就是打表!!!由于素数的个数随着n的不断增大会减少,我们可以通过打表的方法将每一个素数放在数组中。

那么如何实现呢?其实我们可以通过两个基本数相乘,得到一个合数,并将它在数组中标记。2*2,2*3,2*4...3*2,3*3,3*4...通过将每一个合数标记,那么剩下的未标记的数就是素数了。用代码实现就是:

int prime(){
	int max=10001;
	int i,j,num[max];
	for(i=0;i<max;i++){
		num[i]=0;
	}
	num[0]=num[1]=-1;
	for(i=2;i<max;i++){
		for(j=2*i;j<max;j+=i){
			num[j]=1;
		}
	}
	for(i=0;i<max;i++){
		if(num[i]==0){
			printf("%d ",i);
		}
	}
}

以上就是我们常用并且高效的判断质数的方法,可以收藏以备不时之需

接下来我们通过孪生质数这个题目,来实战一下吧!

问题描述

  差为2的两个素数被称为孪生素数对,例如3和5, 11和13.
  给定一个区间,请输出区间内所有的孪生素数对.

输入格式

  两个正整数a,b,其中a<b,以空格分开

输出格式

  区间[a,b]内的所有孪生素数对,按从小到大顺序。每行一个素数对,其中小的在前,大的在后,以空格分开。
  如果区间内没有素数对的话,输出-1.

样例输入

2 15

样例输出

3 5
5 7
11 13

样例输入

14 18

样例输出

-1

看完题目,相信大家一定知道该如何去做了吧。没错,就是我们高效且暴力的打表,将[a,b]内的所有数放在数组,进行打表,就可以知道那些是合数,那些是素数了。最后通过判断 i 和 i+2是不是都是素数,是则输出,并对ans=1作为标记区间内出现素数,不是则过,循环判断结束后,再判断是否出现素数,若未出现即ans=0,输出-1,否则结束。

看看代码如何实现:

#include<stdio.h>
void prime(int *num,int b) {
	num[1]=1;
	int i,j;
	for(i=2; i*i<=b; i++) {
		if(!num[i]) {
			for(j=i*i; j<=b; j+=i) {
				num[j]=1;
			}
		}
	}
}
int main() {
	int a,b,i,ans=0;
	scanf("%d%d",&a,&b);
	int num[b+1];
	for(i=0; i<=b; i++) {
		num[i]=0;
	}
	prime(num,b);
	for(i=a; i<=b-2; i++) {
		if(!num[i] && !num[i+2]) {
			printf("%d %d\n",i,i+2);
			ans=1;
		}
	}
	if(!ans){
		printf("-1");
	}
	return 0;
}

欢迎大家订阅小编的每日一题专栏,会每天更新,都是用心准备的哦!

若有不同思路,欢迎评论区留言,看到必回,Goodnight!

  • 9
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我的代码no摆烂

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

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

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

打赏作者

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

抵扣说明:

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

余额充值