法一:暴力枚举
超时
class Solution:
def countPrimes(self, n: int) -> int:
#暴力枚举超时
def isprime(x):
if x==1:
return False
for i in range(2,int(sqrt(x))+1):
if x%i==0:
return False
return True
if n in [0,1]:
return 0
cnt=0
for i in range(2,n):
if isprime(i):
cnt+=1
return cnt
法二:埃氏筛法
执行用时:1944 ms, 在所有 Python3 提交中击败了21.02%的用户
内存消耗:67.1 MB, 在所有 Python3 提交中击败了12.21%的用户
#埃氏筛法
if n in [0,1]:
return 0
#prime=[]
cnt=0
ht=[]#哈希列表初始化
for i in range(n):
ht.append(0)
for i in range(1,n):
if i==1:
ht[1]=1
if ht[i]==0:
cnt+=1
#prime.append(i)
for j in range(i*i,n,i):#从i*i开始,而非i*2
ht[j]=1
return cnt
法三:线性筛法
关键:每个合数只会被其最小的质因数删去,从而保证每个数只被标记一次,从而达到O(n)的时间复杂度。
执行用时:3580 ms, 在所有 Python3 提交中击败了8.66%的用户
内存消耗:79.8 MB, 在所有 Python3 提交中击败了8.91%的用户
class Solution:
def countPrimes(self, n: int) -> int:
if n in [0,1]:
return 0
cnt=0
prime=[]
ht=[]#哈希列表初始化
for i in range(n):
ht.append(0)
for i in range(1,n):
if i==1:
ht[1]=1
if ht[i]==0:
prime.append(i)
#线性筛的关键,i没有选择,乘的倍数有讲究。(质数序列)
j=0
while j<len(prime) and i*prime[j]<n:
ht[i*prime[j]]=1
if i%prime[j]==0:#i是合数则跳出.因为合数能删掉的数一定可以被它的质因子删掉。
break
j+=1
return len(prime)
法四:奇数筛法
非线性。比如45=3×15=5×9会被筛两次
1828 ms 67.2 MB Python3
class Solution:
def countPrimes(self, n: int) -> int:
if n in [0,1,2]:
return 0
ht=[]#哈希列表初始化
for i in range(n):
ht.append(0)
for i in range(3,n,2):
if ht[i]==0:
#奇数筛的关键:从头到尾略过偶数
j=i
while i*j<n:
ht[i*j]=1
j+=2
cnt=1#2
for i in range(3,n,2):
if ht[i]==0:
cnt+=1
return cnt