这一次呢,与之前所写的博客联动一下。
因为之前是对素数进行判断,那么这篇博客呢,就来完成PAT乙级中的1007这道题,也就是实现素数对猜想。
先来提一提该题目的要求:定义一个dn=pn+1 - pn, 其中呢pi是第i个素数,显然当素数pn+1为3时候,pn为2时,有满足dn=1,那么素数对猜想主要是为了满足dn=2的时候,满足该要求的素数对有多少对。
以20为例,显然存在3、5/5、7/11、13/17、19 这样四对素数对。
而我们要实现的,就是用代表来把这最后有多少对素数对的数量给输出出来。
审题分析,理清逻辑,流程图
要完成这道题目,其实难度不大,我们先理清逻辑:
1、先输入一个正整数。
2、要对输入的正整数从2开始先进行素数判断,这是我们之前那篇博客讲过的。
3、之后要进行条件语句判断,也就是判断pn+1-pn是否等于2,如果等于2,那就要进行计数。
流程图如下:
该流程图还是以串行结构为主。
代码实现
如该流程图所示,在知道了该题目的逻辑后,要实现该题目也非常简单了。
1、用scanf来输入整数N。
2、因为我们之前说过,要判断素数,其实非常简单,只需要把它与除了1与它自身以外的所有自然数相除,看能否整除,余数是否为零,如果为零,那就说明该数不是素数,反之,则说明该数为素数。
3、这道题可不是单纯的输入一个数进行判断,我们需要输入一个数,对它进行遍历,也就是用到一个for循环,而且要注意,是从2开始的,因为2是最小的素数,1并不是素数,之后,要再把该遍历的数与比它小且也是从2开始的素数相除,看能否整数来判断是否为素数。
这里判断是否为素数也同样是用count来计数然后对count数量大小进行判断得到的。
最后呢,再对pn+1-pn是否等于2来进行一定的判断,如果等于2,那也要开始计数,我这里用了一个cout来代替,好记忆一些。
#include<stdio.h>
int main(){
int N = 0;
int i = 0;
int j = 0;
int count = 0;
int cout = 0;
int pn = 2;
int pm;
scanf("%d", &N);
for(i = 2; i <= N; i++){
for(j = 2; j < i; j++){
if(i%j == 0){
count++;
break;
}
else{
count = 0;
}
}
if(count == 0){
pm = i;
if(pm-pn==2){
cout++;
}
pn = pm;
}
}
printf("%d", cout);
}
测试结果:
最后的结果却让我大跌眼镜,该程序竟然超时了!!!
超时的原因在于时间复杂度太大,时间复杂度为O(n^2),或者说该程序计算了许多无效数据,导致最终的结果超时了,实在令人难以理解。
所以,我开始排查,并在网上找寻相关资料。
分析出一个原因:那就是我用来判断素数的方法比较差。
其实判断是否为素数,还有更简便的方法。
试想一下,给定一个值20,我们要判断它不是素数,是不是只需要除以2即可,同理,给定一个值21,它只要除以3就可以得到它不是素数,而至于4、6、8都可以这样得到。
仔细看,是否能发现,这些数的因子是不是都比它们的平方根要小。
也就是说,要判断这些数不是素数,只需要遍历到它们的平方根之前即可,也就是除到它们的平方根之前,那平方根之后的数据不就可以不计算了么。
想到这儿,我就赶紧去找C语言中平方根的方法了。
主要是用到sqrt函数,所以说,只需要把i定义成平方根即可,而且用到的库函数为#include<math.h>
代码实现
#include<stdio.h>
#include<math.h>
int main(){
int N = 0;
int i = 0;
int j = 0;
int count = 0;
int cout = 0;
int pn = 2;
int pm ;
scanf("%d", &N);
for(i = 2; i <= N; i++){
int s = sqrt(i);
for(j = 2; j <= s; j++){
if(i%j == 0){
count++;
break;
}
else{
count = 0;
}
}
if(count == 0){
pm = i;
if(pm-pn==2){
cout++;
}
pn = pm;
}
}
printf("%d", cout);
}
测试结果:
总结
总的来说,这道题难度不大,但是一定要注意,是否计算了无效数据,以及时间复杂度是否太大,m*n和n*n之间也是有着比较大的差距的。