埃氏筛法求质数
题目
输入两个数m和n(m<=n),先计算a = m(m+1)(m+2)……(n-2)(n-1)n,然后再统计2到a之间(包含a)存在多少个合数。
暴力枚举
暴力枚举是最简单也是最基础的做法,直接从定义出发,遍历2到a之间的每个数,依次通过取余的方法去判断:
m = int(input()) n = int(input()) a = 1 for i in range(m, n + 1): a *= i c = 0 for i in range(2, a + 1): for j in range(2, i): if i % j == 0: c += 1 break print(c)
埃氏筛法
使用暴力枚举很容易就会发现问题,当m取1,n取10的时候,看起来很小,但是这个时候a的值已经变成了3628800。对于这样的数,暴力枚举显然已经不可接受了,这里就需要介绍一下,埃氏筛法了。
原理:因为一个合数必定可以分解出至少一个质因数,所以要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
思想:我们可以从第一个已知的质数2开始遍历,标记它的倍数。当我们遍历到某个数i时,如果这个数i还没有被标记过,那证明在i之前没有它的质因数,那i就肯定是质数,于是我们又去标记i的倍数。如果i已经被标记了,i为合数,直接跳过,继续往后遍历。
解法:有了上面的思想之后,如何去标记数就似乎最大的问题,我们可以建立一个列表ls,列表的索引对应数i,该索引对应的元素取布尔值(或者0和1),表示是否被标记。ls[i] == True,就表示这个数i已经被标记了。
比传统的暴力枚举效率会高非常多。
import math m = int(input()) n = int(input()) a = 1 for i in range(m, n + 1): a *= i # 因为需要ls[a],所以列表的长度为a+1,用0表示没被标记,1表示标记了,最后用count数1的个数就可以了。 ls = [0 for i in range(a + 1)] # 只遍历到a的平方根就可以了,如果平方根左侧没有因数,那右侧必定也没有。 for i in range(2, int(math.sqrt(a + 1))): if not ls[i]: j = 2 while i * j <= a: ls[i * j] = 1 j += 1 print(ls.count(1))
欧拉筛
其实仔细思索,埃氏筛也会有很多的重复计算,比如12,在质因子2的时候会被筛一次,在质因子3的时候也会筛一次,如果数据足够大,同一个合数会被重复的筛很多次。欧拉筛和埃氏筛的核心原理是一样的,但是欧拉筛做了一个很重要的改进,即:每个合数只被他最小的质因子筛一次。
具体的实现:
- 和埃氏筛一样,定义一个列表ls来表示每个数是否被标记,初始全部表示为质数,即未被标记,然后去筛掉合数
- 再建一个列表primes,来存已经找到的质数,当我们遍历i的时候,如果发现i未被标记,则记录下这个质数
- 对于每一个i,遍历所有已有的质数,将他们的i倍数全部筛掉,然后,如果发现当前遍历的质数p_n是当前数字i的质因子,则直接break,因为我们要保证每个合数只被它最小的质因子筛掉一次。例如当i=4时,此时存在已有质数2、3,那么就会标记8和12,当i=6时,此时存在已有质数2、3、5,那么就会标记12、18、30,此时会发现12被重复标记了,所以在i=4时,当遇到它的质因子2时,就直接标记8,然后break,不在对3*4的数做标记了
- 标记时注意判断是否越界
a = int(input()) # 每个数的状态,0是质数,1是合数 ls = [0 for _ in range(a + 1)] # 记录已经找到的质数 primes = [] for i in range(2, a+1): # 如果i是质数,记录下这个质数 if not ls[i]: primes.append(i) # 开始筛,筛掉所有已有质数的i倍 for p_n in primes: # 避免越界,只找范围内的数字 if i * p_n > a: break ls[i * p_n] = 1 # 每个数只被他的第一个质因子筛一次,避免重复筛 if i % p_n == 0: break print(primes)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】