这个随笔我是在写以下PAT上题目过来写的,以下是题目测试点
题目就是很简单就能AC,但是对于是判断素数这个问题似乎我一学C语言的时候就已经接触了,对于普通的先开根号在其范围内直接循环取余我就不重复了。
- 介绍第一种方法:
摘抄来自huang_mao_xin的帖子
证明:令x≥1,将大于等于5的自然数表示如下:
······ 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ······
可以看到,不在6的倍数两侧,即6x两侧的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们一定不是素数,再除去6x本身,显然,素数要出现只可能出现在6x的相邻两侧。这里有个题外话,关于孪生素数,有兴趣的道友可以再另行了解一下,由于与我们主题无关,暂且跳过。这里要注意的一点是,在6的倍数相邻两侧并不是一定就是质数。
根据以上规律,判断质数可以6个为单元快进,即将方法(2)循环中i++步长加大为6,加快判断速度,代码如下:
bool Isprime(int num) { if (num < 2)return false; //两个较小数另外处理 if (num == 2 || num == 3) return true; //不在6的倍数两侧的一定不是质数 if (num % 6 != 1 && num % 6 != 5) return false; int tmp = sqrt(num); //在6的倍数两侧的也可能不是质数 for (int i = 5; i <= tmp; i += 6) if (num %i == 0 || num % (i + 2) == 0) return false; //排除所有,剩余的是质数 return true; }
第一眼看到的时候感觉这种方法似乎真的很省时,但是拿PAT的测试没有通过,所有问题待定,以后补充
- 第二个方法:叫Eratosthenes筛法,
原理:如果一个数是素数,那么这个数的倍数一定不是素数,把所有的非素数都去掉,但是这个算法会有冗余,算法效率要比O(n)低,这个方法适合用于筛选出1到N的所有素数这类问题。
bool flag[N]; void findPrime(int num){ for (int i = 0; i <= num; i++){ flag[i] = true; } flag[0] = flag[1] = false; for (int i = 2; i <= num; i++){ if (!flag[i]) continue; for (int j = i*i; j <= num; j += i){ flag[j] = false; } } }
未完待续。。。。