def countPrimes(self, n: int) -> int:
def is_primes(c):
"""
判断c是否为质数
"""
for i in range(2, int(pow(c, 0.5)) + 1):
if c % i == 0:
return False
return True
ans = 0
for j in range(2, n):
if is_primes(j):
ans += 1
return ans
"""
解法三(更不暴力的暴力算法):
【思路】
在解法二的基础上,我们发现其实如果已经除了2,那么再除4、6等偶数都是没有意义的。
因此,我们将算法优化为只除以之前已经发现的质数,得到如下算法:
"""
def countPrimes(self, n: int) -> int:
prime_list = []
for c in range(2, n):
for i in prime_list:
if c % i == 0:
break
else:
prime_list.append(c)
return len(prime_list)
"""
解法四(使用数组标记合数):
【思路】
既然后面的数我们已经是通过之前除以之前发现的质数来判断是否为质数,那没有其实已经没有必要再继续使用耗时更高除法了。
我们可以建立一个数组,用以标记各个数是否为质数;当我们每发现一个质数,就遍历将所有该质数的倍数标记为合数;这种方法叫做“厄拉多塞筛法”。
由此,我们得到如下算法,虽然时间复杂度为O(n^2),但是不用再使用除法了:
"""
def countPrimes(self, n: int) -> int:
num_list = [True for _ in range(n)]
for i in range(2, n):
if num_list[i]: # 如果i为质数(不是任何质数的倍数)
for j in range(2 * i, n, i):
num_list[j] = False
ans = 0
for i in range(2, n):
if num_list[i]:
ans += 1
return ans
"""
解法五(优化解法四):
【思路】
因为我们在标记7的倍数时,14、21、28、35、42都已经被2、3、5标记过了,即7*7以下的7的倍数都已经被标记了,所以,我们只需要从7*7向上标记7的倍数就可以了。
因此,当我们判断到n平方根(即标记完小于等于n平方根的最大质数)后,就不用再判断和标记了。
由此,我们得到了如下算法:
"""
def countPrimes(self, n: int) -> int:
num_list = [True for _ in range(n)]
for i in range(2, int(pow(n, 0.5)) + 1):
if num_list[i]: # 如果i为质数(不是任何质数的倍数)
for j in range(i * i, n, i):
num_list[j] = False
ans = 0
for i in range(2, n):
if num_list[i]:
ans += 1
return ans
#解法六(优化解法五):
#【思路】
#因为在Python中,Python的内置语句往往会比我们自己写的算法要更快,因此我们更多地使用一些Python的#内置语句来优化算法。
#同时,在生成各元素相同的列表时,“列表生成式”的运行速度比“列表乘以常数”的运行速度要慢很多,不再使#用列表生成式。
def countPrimes(self, n: int) -> int:
if n < 2:
return 0
num_list = [True]*n
num_list[0], num_list[1] = False, False
for i in range(2, int(pow(n, 0.5)) + 1):
if num_list[i]: # 如果i为质数(不是任何质数的倍数)
num_list[i * i::i] = [False] * ((n - i * i - 1) // i + 1) # 因为要包含i*i所以需要+1;因为n不在列表里,所以需要-1
return sum(num_list) # True就是1,False就是0,可以直接统计
解题思路
注意 题目说的是小于n的所有数字中质数的个数 所以是 is_prime = [True]*(n)
表示我们考虑is_prime[1],...,is_prime[n-1]
我们从2向后遍历,每遇到一个数字,将其倍数所对应的 is_prime 设为False,
因此遇到新的数字num,is_prime[num]=True说明它不是任何2..num-1的数字的倍数,即质数。
代码
def countPrimes(n):
is_prime = [True]*(n)
ans = 0
for num in range(2,n):
if is_prime[num]:
ans+=1
# 右边界:因为数字最大是n-1 所以只需要到(n-1)//num 右边是开区间 所以+1
for k in range(1,(n-1)//num+1):
is_prime[num*k]=False
return ans
作者:yuer-flyfly
链接:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-yi-ci-bian-li-python-by-y-dnqr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。