一、题目描述
给定整数 n
,返回 所有小于非负整数 n
的质数的数量 。
示例 1
输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2
输入:n = 0
输出:0
示例 3
输入:n = 1
输出:0
提示:0 <= n <= 5 * 10^6
二、代码
代码如下:
class Solution:
def countPrimes(self, n: int) -> int:
if n < 2:
return 0
isPrime = [1] * n
isPrime[0] = isPrime[1] = 0 # 0和1不是质数,先排除掉
# 埃式筛,把不大于根号 n 的所有质数的倍数剔除
# int(n ** 0.5):这是因为如果 i 存在大于其平方根的因子,那么必定也存在小于其平方根的因子。
for i in range(2, int(n ** 0.5) + 1):
# 排除所有 质数 的倍数的数(将其对应数组位置置零)
# ①2是质数,排除 2 的倍数的数:4,6,8,10,...
# ②3是质数,排除 3 的倍数的数:6,9,12,15,...
# ③ 4 不是质数,不需要排除(原因是之前在排除2的倍数时,已经包含了4的倍数)
# ④5是质数,排除 5 的倍数的数:10,15,20,25,...
# ⑤ 6 不是质数
# ⑥7是质数,排除 7 的倍数的数:14,21,28,35,...
# ...
if isPrime[i]: # 如果当前的数为质数(isPrime[i] = 1),则执行排除操作,排除其倍数的所有数
# 切片操作:区间为 [i*i, n) , 步长为 i; ((n - 1 - i * i) // i + 1)表示排除数组的长度
isPrime[i * i:n:i] = [0] * ((n - 1 - i * i) // i + 1)
print(sum(isPrime))
return sum(isPrime)
三、解题思路
本题如果使用暴力的遍历法进行求解,则会导致超时,所以需要改变策略,这里则使用了著名的埃拉托斯特尼筛法,简称埃式筛,也叫厄拉多塞筛法:
要得到自然数 n 以内的全部质数,必须把不大于 根号n 的所有质数的倍数剔除,剩下的就是质数。
所以本题的解题思路为排除所有 质数 的倍数的数,剩下来的数则是质数。具体解题方法如下:
① 构建长度为 n
的全为 1
的数组 isPrime
,isPrime[i]=1
表示当前数为质数。0,1
不是质数,所以将isPrime[0],isPrime[1] = 0
,表示排除掉这两个数。
② 从2开始遍历连续的自然数,右界限为 根号n
,将当前数为质数对应的所有倍数的数全部排除.
③ 最后将数组isPrime
中的值求和就是所有质数的数量。返回sum(isPrime)
即可。
下面是具体例子:
①i=2 是质数,排除 2 的倍数的数:4,6,8,10,...
②i=3 是质数,排除 3 的倍数的数:6,9,12,15,...
③i=4 不是质数,不需要排除(原因是之前在排除2的倍数时,已经包含了4的倍数)
④i=5 是质数,排除 5 的倍数的数:10,15,20,25,...
⑤i=6 不是质数
⑥i=7 是质数,排除 7 的倍数的数:14,21,28,35,...
...