计数质数-LeetCode
204. 计数质数 (Count Primes)
🎯 问题描述(来源于LeetCode)
描述:给定整数 n,返回所有小于 n 的非负质数的数量。
说明:
- 质数:在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
- 注意是 小于
n,不包含n本身。
示例:
- 示例 1:
1
2
3输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个,分别为 2, 3, 5, 7。 - 示例 2:
1
2
3输入:n = 0
输出:0
解释:没有小于 0 的数。
💻 解题思路
思路1:枚举优化(试除法)
这是一个典型的枚举算法应用。我们需要遍历从 2 到 n-1 的每一个数字,并判断其是否为质数。
核心优化点(剪枝):
单纯枚举 1 到 n 判断是否整除的时间复杂度是 。利用数学性质可以将其优化至 :
- 平方根性质:如果一个数 有因数,那么必然有一个因数小于或等于 。
- 实现:在判断质数函数
Iszhi中,循环只需要从2遍历到int(n ** 0.5) + 1即可。
算法步骤:
- 特判:处理
n <= 2的情况,直接返回 0(因为小于2的数中没有质数)。 - 外层循环:遍历
2到n-1的每一个数i。 - 内层判断:调用
Iszhi(i)函数检查i是否为质数。 - 计数:如果是质数,计数器
count加 1。
思路1:代码实现
1 | class Solution: |
思路1:📊 性能分析
复杂度验证
- 时间复杂度:
- 外层循环需要遍历 个数。
- 每个数进行质数判断需要 。
- 总体复杂度为 。对于大数(如 )可能会超时。
- 空间复杂度:
- 只使用了常数级别的额外变量(
count,i等)。
- 只使用了常数级别的额外变量(
💡 思考
1. 为什么循环上限是 int(n ** 0.5) + 1?
n ** 0.5:计算 的平方根。int():将浮点数向下取整为整数。+ 1:因为range函数是左闭右开区间(不包含结束值)。如果不加 1,当 恰好是完全平方数(如 25)时,循环会在 4 结束,导致漏掉 5 这个因数,从而错误地判定 25 是质数。
2. 进阶思考:埃拉托斯特尼筛法
虽然上述代码逻辑正确,但在处理大数(如 )时效率较低。
- 更优解法:可以使用埃拉托斯特尼筛法 (Sieve of Eratosthenes)。
- 原理:创建一个长度为 的布尔数组,初始假设所有数都是质数。从 2 开始,将 2 的所有倍数(4, 6, 8…)标记为非质数,然后找下一个未被标记的数(3),再标记 3 的倍数。以此类推。
- 复杂度:时间复杂度可优化至 ,是解决此类问题的最优解之一。
3. 易错点总结
- 边界处理:
n = 0或n = 1时,循环range(2, n)不会执行,直接返回 0,这是正确的,但逻辑必须清晰。 - 数据类型:
n ** 0.5返回的是浮点数,必须用int()转换为整数才能用于range。
思路2:埃拉托斯特尼筛法
思路2:代码实现
1 | class Solution: |
思路2:📊 性能分析
- 执行用时分布:1581ms击败46.97%
- 消耗内存分布:56.79MB击败81.29%
复杂度验证 - 时间复杂度:
- 空间复杂度:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






