写一个求第n个质数的算法
一、问题分析
可以分为两步,第一步判断一个数是否是质数,第二步返回第n个质数。
二、算法实现
质数是不能被1和其自身之外的整数整除的正整数,因此只需要用一个数去对所有比它小的整数取余,如果余数有0,表示能被整除,则不是质数1
2
3
4
5
6
7
8function isPrime(n){
for(var i = 2; i < n; i++){
if(n % i === 0){
return false
}
}
return true
}
然后从2开始依次判断每个整数是否为质数,直到统计到第n个质数后结束。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function prime(n){
let m = 0
let i = 2
while(m < n){
if(isPrime(i)){
m++
}
i++
}
return i-1;
}
prime(1)//2
prime(2)//3
prime(3)//5
prime(4)//7
三、算法优化
1、平方根
由于如果一个正整数在2到n的平方根之间都不能被整除就可以确定这个数是质数,所以判断质数时只用对2到n的平方根之间的整数取余。
1 | function isPrime(n){ |
2、2的倍数
另外,由于除2以外所有的偶数都不是质数,所以在循环时可以直接排除,这样取余的数将会少一半
1 | function isPrime(n){ |
3、3的倍数
由于除3以外,所有的3的倍数都不是质数,所以在循环时可以直接排除,这样取余的数将会又少1/3。要在循环时跳过2的倍数和3的倍数,可以把每6个数分为一组,例如第一组:[1,2,3,4,5,6],第二组:[7,8,9,10,11,12],第m组:[6m+1,6m+2,6m+3,6m+4,6m+5,6m+6],除去2的倍数和3的倍数,剩下的就是6m+1和6m+5。
写一个循环,打印出0到n之间的6m+1和6m+5
1 | let n = 50 |
如此,判断是否是质数的函数就可以改造为
1 | function isPrime(n){ |
4、5的倍数
由于除5以外,所有的5的倍数都不是质数,所以在循环时可以直接排除,这样取余的数将会又减少1/5。要在循环时跳过2的倍数、3的倍数和5的倍数,可以把每30个数分为一组,第m组:[30m+1,30m+2,30m+3,…,30m+30],除去2的倍数、3的倍数和5的倍数,剩下的就是30m+1、30m+7、30m+11、30m+13、30m+17、30m+19、30m+23、20m+29。
写一个循环,打印出上面这些数
1 | let n = 100 |
如此,判断是否是质数的函数就可以改造为
1 | function isPrime(n){ |
5、最终代码
以此类推,还可以确定所有7的倍数、11的倍数、13的倍数等都不是质数,但是越往后,可以排除的数越少,而要在循环里判断条件中列出来的数越多,可以想象,极端情况下就是手动列举出所有的质数。
综合考虑代码的简洁性和效率,只需要排除2的倍数和3的倍数即可。
有了判断一个数是不是质数的方法后,就需要从2开始往后循环,找出第n个质数。同样,这里也可以直接跳过2的倍数和3的倍数。
最终代码为
1 | function isPrime(n){ |
四、总结
这题的核心在于对质数的判断,从定义上来说要判断一个数是否是质数,只需要判断这个数能否被每一个小于该数的整数整数即可。但是实际上我们不用挨个判断每一个数,可以根据质数的特性优化算法。