问题描述
我们知道第一个质数是 2、第二个质数是 3、第三个质数是 5……那第 2020 个质数是多少?
解决方案
当看到这种寻找质数的问题,很多人第一时间想到的便是二重循环暴力查找。但如果要找第2020个质数、第9999个质数,这种暴力方法查找的速度就太慢了。
这个时候就可以使用筛法来提高运行速度,本文介绍的是埃氏筛法。因为质数的倍数一定不是质数,因此将质数的倍数直接标记成合数,标记后列表中没被标记且没记为质数的最小的那个数一定是质数(1除外),以此达到快速筛选质数的目的。
例如:筛选1-10之间的质数。
1不是质数,直接看2-10。
(质数标记为红色,合数标记为蓝色)
图 2.1 2-10列表
最小的数是2,所以2是质数,标记4,6,8,10
图 2.2 第一次标记
此时没被标记且没记为质数的最小的数是3,所以3是质数,标记6,9
图 2.3 第二次标记
此时没被标记且没记为质数的最小的数是5,所以5是质数,标记10
图 2.4 第三次标记
此时没被标记且没记为质数的最小的数是7,所以7是质数
图 2.5 第四次标记
代码:
def eratosthenes(n): lis = [0 for i in range(n + 1)] # 初始化为0,0表示质数,1表示合数 lis2 = [] # 存质数 for i in range(2, n + 1): if lis[i] == 0: # 如果没有被标记就加到Lis2 lis2.append(i) for j in range(i * 2, n + 1): if j % i == 0: # 记录合数 lis[j] = 1 return lis2 |
结语
虽然和暴力查找相比,埃氏筛快了很多。但是如果大家仔细看埃氏筛法标记合数的情况可以很清楚的看到有很多数字是被重复标记的。比如10,质数是2时会标记,质数是5时也会标记。那么我们是不是可以找一个办法解决重复标记的问题?