统计所有小于非负整数 n 的质数的数量。
示例:
输入: 10 输出: 4 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
一般方法,也就是一般人都会用的,将数从2到它本身逐个比较是否能被整除,就能得到结果。但这种方法复杂度是在0(n2)所以无法AC。
但是通过数学特性可以了解到,最多只要判断到这个数的开方数的时候,就可以知道这个数是否为质数了,所以复杂度减少了一半,也就可以让代码AC,但是时间用时也是很大的。
评论区学到的方法是,从2开始,剔除2到n中所有2的倍数,因为2的倍数都是非质数,然后找到3,同样剔除3的所有倍数,依次类推,得到最后的答案。
当然也可以应用数学特性将这个过程缩短,代码中不再演示
代码如下:(逐个比较)
import math class Solution: def isPrime(self, n: int) -> bool: for i in range(2, math.floor(math.sqrt(n))+1): if n % i == 0: return False return True def countPrimes(self, n: int) -> int: count = 0 for i in range(2, n): if Solution.isPrime(self, i): count += 1 return count
代码如下:(剔除倍数)
class Solution: def countPrimes(self, n: int) -> int: if n < 3: return 0 else: isPrime = [1] * n isPrime[0], isPrime[1] = 0, 0 for i in range(2, n): t = 2 if isPrime[i] == 1: while i*t < n: isPrime[i*t] = 0 t += 1 return sum(isPrime)
剔除倍数的优化版本,摘自评论区:
# author: https://leetcode-cn.com/yuan-lei-yang/ def countPrimes(self, n: int) -> int: if n < 3: return 0 else: # 首先生成了一个全部为1的列表 output = [1] * n # 因为0和1不是质数,所以列表的前两个位置赋值为0 output[0],output[1] = 0,0 # 此时从index = 2开始遍历,output[2]==1,即表明第一个质数为2,然后将2的倍数对应的索引 # 全部赋值为0. 此时output[3] == 1,即表明下一个质数为3,同样划去3的倍数.以此类推. for i in range(2,int(n**0.5)+1): if output[i] == 1: output[i*i:n:i] = [0] * len(output[i*i:n:i]) # 最后output中的数字1表明该位置上的索引数为质数,然后求和即可. return sum(output)