写在前面的话:
大家好,我是一名正在努力学习数据结构和算法的新手。这篇文章是我在学习python的各类数据结构以及基础算法过程中的一些笔记和心得,希望能和同样在学习该方面知识的朋友们分享。由于我的知识有限,文章中可能存在错误或不准确的地方,欢迎大家在评论区提出建议和指正。我非常期待大家的反馈,以便我能不断学习和进步。同时,我也会在文章中注明参考的资料,以示对原作者的尊重。
PS:本帖以记录学习心得和刷题记录解析为主,没有其他大博主那么专业,但是简单易懂^-^
本贴的其他相关学习笔记资料可以通过订阅专栏获取,喜欢的小伙伴可以多多点赞+关注呀!后续会 持续更新相关资源的~
今天是我们备战的第一天,我们将从埃拉托斯特尼筛法(Sieve of Eratosthenes)和欧拉筛开始,这是一种古老而高效的算法,用于找出一定范围内的所有质数。通过今天的学习,我们不仅会理解埃氏筛和欧拉筛的原理和实现,还将通过刷题来加深对枚举算法的理解。
学习资源指路:
埃氏筛/欧拉筛教程以及代码实现-参考文章:欧拉筛【力扣周赛 326】LeetCode_哔哩哔哩_bilibili
题目:
关于质数的基本知识:大于1且只能被自身和1整除的数。(1不是质数!!
暴力骗分解法1-埃氏筛(因为超时只能通过部分用例):枚举(这里直接使用的就是埃氏筛解法,直接通过遍历n可能范围内的所有数,以倍数删除的方式筛选出质数并标记,最后在根据n选出满足题目条件的质数,再用len函数计算个数即可)
class Solution:
def countPrimes(self, n: int) -> int:
MX=5*10**6+1
primes=[]
count=0
data_list=[True]*MX
for i in range(2,MX):
if data_list[i]:
primes.append(i)
for j in range(i*i,MX,i):
data_list[j]=False
primes.append(MX)
primes.append(MX)
primes2=[1 for i in primes if i<n]
return len(primes2)
为什么对于答案primes列表后面还需要加上
primes.append(MX)
primes.append(MX)
保证primes不溢出(加俩大的数,避免计算机计算的结果超过了列表最大范围)
解法2:欧拉筛(也叫做线性筛)
目标:每个合数只被划掉一次
基本思想:每个数都乘上小于or等于其本身的质数,从而把该乘积结果对应的数字筛选掉。但是在筛选过程中会重复划掉一些相同的合数。
优化:使得合数只被最小的质因子划掉--每个数乘上小于等于它的质因子即可
先标记后再判断:如果当前就是最小质因子,停止内循环,前进到下一个i
class Solution:
def countPrimes(self, n: int) -> int:
MX=5*10**6+1
primes=[]
count=0
data_list=[True]*MX
for i in range(2,MX):
if data_list[i]:
primes.append(i)
for p in primes:
if p*i>=MX:
break
data_list[p*i]=False
if i % p ==0: #这里为什么要取模?
break
primes.append(MX)
primes.append(MX)
primes2=[1 for i in primes if i<n]
return len(primes2)
关于这里为什么要取模的问题:因为我先把他俩的乘积(就是合数)标记为false之后,我需要判断此时的p是否就是i的最小质因子,能被整除就说明是,比如4/2=2---0 再让4*3的话12的最小质因子就不是4,而是2了,就会有重复的删除操作,不够高效。
但是,前两种解法经过运行均超时,这是因为这两种解法把n的最大范围内所有的质数都找出来了,实际上只需要根据实际输入数据的n作为上界来找所有质数即可,这样可以大大减少时间复杂度。
埃氏筛正确解法:
class Solution:
def countPrimes(self, n: int) -> int:
count=0
data_list=[True]*n
for i in range(2,n):
if data_list[i]:
count+=1
for j in range(i*i,n,i):
data_list[j]=False
return count
当然了,这里在列表中表示质数的方式由True or False变成0 or 1 会更快,这里是便于理解。
欧拉筛/线性筛正确解法:
class Solution:
def countPrimes(self, n: int) -> int:
primes=[]
count=0
data_list=[1]*n
for i in range(2,n):
if data_list[i]==1:
count+=1
primes.append(i)
for p in primes:
if i*p >=n:
break
data_list[p*i]=0
if i%p==0:
break
return count
对于两种筛选质数方法得理解:
埃氏筛:通过往后跳跃得方式筛出合数(i*i);
欧拉筛:通过与前面得质数乘积,筛出后面得合数+最小质因子才能筛出合数得判断(i*p,i%p==0)
最后,感谢每一位阅读这篇文章的朋友,你们的反馈对我来说非常宝贵。如果有任何问题或建议,请随时告诉我。让我们一起学习和进步吧!如果您喜欢我的内容,别忘了点赞和关注哦,我会定期分享更多有价值的信息。