【中等】力扣算法题解析LeetCode204:计数质数

关注文末推广名片,即可免费获得本题测试源码

题目来源:LeetCode204:计数质数

问题抽象: 设计算法高效计算小于非负整数 n质数数量(统计范围 [0, n-1]),需满足以下核心需求:

  1. 质数定义

    • 质数需大于 1仅能被 1 和自身整除(如 2,3,5,7,...);
    • 特殊值:01 非质数。
  2. 高效计算策略

    • 埃拉托斯特尼筛法
      • 初始化长度 n 的布尔数组 isPrime(默认 true);
      • 2 开始遍历至 √n,若 isPrime[i]true,则标记 i 的所有倍数为 false
    • 空间优化:使用原生布尔数组(非位图)。
  3. 性能约束

    • 时间复杂度 O(n log log n)(埃氏筛理论最优);
    • 空间复杂度 O(n)(存储标记数组);
    • 支持 n ≤ 5×10^6(需通过所有测试用例)。
  4. 边界处理

    • n=0n=1 时输出 0(无数值大于 1);
    • n=2 时输出 0(小于 2 的质数数量为 0);
    • n=3 时输出 1(仅质数 2);
    • 大数优化:
      • 外层循环终止于 √n(避免冗余标记);
      • 内层标记从 开始(跳过已处理倍数)。

输入:整数 n(值域 [0, 5×10^6]
输出:整数(小于 n 的质数数量)


解题思路

核心算法:埃拉托斯特尼筛法(优化版)

  1. 特殊处理:当 n ≤ 2 时,直接返回 0(因为小于 2 的质数为 0)。
  2. 布尔数组标记非质数:创建长度为 n 的布尔数组 notPrime,索引表示数字,true 表示非质数。
  3. 预处理偶数为非质数:除了数字 2,所有偶数都不是质数。遍历所有偶数索引(≥4),标记为 true
  4. 计数质数:初始化质数计数器为 1(数字 2 是质数)。
  5. 遍历奇数:从 3 开始,每次步进 2(只检查奇数):
    • 若当前数未被标记为非质数,则计数器加 1。
    • 若当前数 i 不超过 √n,则标记其奇数倍为非质数(从 i*i 开始,步长 2*i,避免重复标记偶数倍)。
  6. 返回结果:最终计数器的值即为小于 n 的质数数量。

亮点

  • 跳过偶数:外层循环只遍历奇数,减少一半迭代次数。
  • 步长优化:内层标记时步长为 2*i,只标记奇数倍(偶数已预处理)。
  • 提前终止:当 i > √n 时,其倍数已超出范围,无需标记。

代码实现(Java)🔥点击下载源码

class Solution {
    public int countPrimes(int n) {
        if (n <= 2) {
            return 0;
        }
        boolean[] notPrime = new boolean[n]; // 标记非质数
        notPrime[0] = true;
        notPrime[1] = true;
        // 标记所有大于2的偶数为非质数
        for (int i = 4; i < n; i += 2) {
            notPrime[i] = true;
        }
        int count = 1; // 数字2是质数
        int sqrtN = (int) Math.sqrt(n);
        // 遍历奇数:3,5,7,...,n-1
        for (int i = 3; i < n; i += 2) {
            if (!notPrime[i]) { // i是质数
                count++;
                if (i > sqrtN) { // 超过√n时,倍数已超出范围
                    continue;
                }
                // 标记i的奇数倍(i*i, i*i+2i, ...)为非质数
                for (long j = (long) i * i; j < n; j += 2 * i) {
                    notPrime[(int) j] = true;
                }
            }
        }
        return count;
    }
}

代码说明

  1. 初始化处理
    • n ≤ 2 时直接返回 0。
    • 布尔数组 notPrime 标记非质数,默认 false(质数)。
    • 显式标记 0、1 为非质数。
  2. 预处理偶数
    • 循环标记所有大于 2 的偶数(4,6,8,…)为非质数。
  3. 计数与标记
    • 初始化计数器 count = 1(包含质数 2)。
    • 遍历奇数(3 到 n-1):
      • i 是质数(notPrime[i] = false),则 count++
      • i ≤ √n 时,从 i*i 开始,以步长 2*i 标记非质数(避免偶数倍)。
  4. 返回结果:计数器 count 即为小于 n 的质数数量。

提交详情

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达文汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值