新闻详情

新闻详情

首页 / 资讯中心 / 详情

【LeetCode 204. 计数质数】从暴力枚举到埃拉托斯特尼筛法

发布时间:2026/10/1 21:58:28来源:尧图网络
【LeetCode 204. 计数质数】从暴力枚举到埃拉托斯特尼筛法
如果你也是因为超时问题而来请跳转至【LeetCode 204. 计数质数】从暴力枚举到打表预处理题目描述给定整数 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解题思路演进这道题是经典的数论基础题。根据数据范围 n 5 * 10^6我们可以推导出不同算法的时间复杂度表现。方法一暴力枚举会超时 TLE最直观的想法是遍历从 2 到 n-1 的每一个数字 i然后判断 i 是否为质数。判断质数的方法是尝试用 2 到 sqrt(i) 之间的数字去整除 i。代码实现class Solution { public: bool isPrime(int x) { for (int i 2; i * i x; i) { if (x % i 0) return false; } return true; } int countPrimes(int n) { int ans 0; for (int i 2; i n; i) { if (isPrime(i)) ans; } return ans; } };复杂度分析时间复杂度O(N根号N​)。当N5×106时计算量达到十亿级别在 LeetCode 上必定超时。空间复杂度O1。方法二埃拉托斯特尼筛法Sieve of Eratosthenes既然暴力法会超时我们需要一种更高效的算法。埃拉托斯特尼筛法简称埃氏筛是一种古老且经典的质数筛选算法。核心思想如果 x 是质数那么 x 的倍数2x, 3x, 4x...一定不是质数。我们可以从 2 开始遍历将当前数字的倍数全部标记为“合数”。遍历结束后未被标记的数字就是质数。在实现埃氏筛时有一个极其重要的优化细节内层循环从 i * i 开始而不是 2 * i。for (int j i * i; j n; j i) { isPrime[j] false; }为什么可以从 i * i 开始假设当前遍历到的质数是 i。对于 i 的倍数 i * k如果 k i那么 i * k 必然已经被比 i 更小的质数比如 k 的某个质因数筛选过了。例如当 i 5 时5 * 2 10已被 2 筛掉5 * 3 15已被 3 筛掉5 * 4 20已被 2 筛掉。因此为了避免重复标记重复计算我们从 i * i 开始标记即可这是 i 的倍数中第一个尚未被更小质数标记的数字。代码实现 (C)class Solution { public: int countPrimes(int n) { // 边界条件小于等于 2 的数没有质数 if (n 2) return 0; // 创建布尔数组isPrime[i] 表示数字 i 是否为质数 // 初始默认全部为 true (质数) vectorbool isPrime(n, true); // 0 和 1 不是质数 isPrime[0] false; isPrime[1] false; // 从 2 开始筛只需要遍历到 sqrt(n) 即可 for (int i 2; i * i n; i) { if (isPrime[i]) { // 优化从 i * i 开始标记步长为 i for (int j i * i; j n; j i) { isPrime[j] false; } } } // 统计所有标记为 true 的数字 int count 0; for (int i 2; i n; i) { if (isPrime[i]) count; } return count; } };复杂度分析时间复杂度ONloglogN。这是埃氏筛的经典复杂度非常接近于线性时间对于5×106的数据量可以轻松通过。空间复杂度ON。需要一个长度为N的布尔数组来记录状态。由于 vectorbool 在 C 中经过了位压缩优化实际占用内存非常小。进阶拓展线性筛欧拉筛虽然埃氏筛已经足够优秀但在某些极端情况下可能会提到线性筛欧拉筛。埃氏筛的痛点一个合数可能会被多个质数重复标记。例如 12会被 2 标记一次2 * 6也会被 3 标记一次3 * 4存在冗余计算。线性筛的核心思想保证每个合数只会被它的最小质因数筛掉。这样时间复杂度可以降到严格的O(N)。线性筛代码示例class Solution { public: int countPrimes(int n) { vectorint primes; // 存储已找到的质数 vectorbool isPrime(n, true); // 标记数组 int ans 0; for (int i 2; i n; i) { if (isPrime[i]) { primes.push_back(i); ans; } // 核心用当前质数 primes[j] 去筛 i * primes[j] for (int j 0; j primes.size() i * primes[j] n; j) { isPrime[i * primes[j]] false; // 保证每个合数只被它的最小质因数筛掉 if (i % primes[j] 0) break; } } return ans; } };
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Sqoop --direct模式加速原理与实战:何时用、怎么调优 2026/10/1 22:57:10

Sqoop --direct模式加速原理与实战:何时用、怎么调优

开头 用Sqoop导数据慢到怀疑人生?明明集群资源充足,MapReduce任务却像老牛拉车一样,几百万条数据跑个十几分钟都算运气好?如果你也遇到过这种情况,那这篇内容就是写给你的。今天我们只聊一件事:Sqoop的 --…

阅读更多 →
CrewAI多智能体实战:中文环境供应链预警系统搭建 2026/10/1 22:57:10

CrewAI多智能体实战:中文环境供应链预警系统搭建

1. 这不是又一个“AI玩具”,而是能跑通真实业务流的多智能体操作系统你点开 GitHub,看到 CrewAI 项目页上那个醒目的59,237 颗 Star(截至2024年6月实测数据),第一反应可能是:“又一个热度来的快去得也快的A…

阅读更多 →
平面连杆机构动态仿真:从运动分析到动力学优化的完整指南 2026/10/1 22:57:10

平面连杆机构动态仿真:从运动分析到动力学优化的完整指南

前几天帮一个做包装机械的朋友排查一台给料机构的异常振动,他在三维软件里把连杆机构的运动轨迹画得相当漂亮,但样机一跑高速,铰接部位就发烫、整机噪音直线上升。我把他的机构参数拉进动态仿真环境重新走了一遍,速度波动曲线和铰…

阅读更多 →
gpt-image-1生产环境实战:蒙版与Alpha通道避坑指南 2026/10/1 22:57:09

gpt-image-1生产环境实战:蒙版与Alpha通道避坑指南

把 gpt-image-1 接进生产环境这件事,我前后折腾了小两周。模型本身出图质量没什么好挑剔的,真正让我加班到凌晨的,是蒙版(mask)和 Alpha 通道。很多文档只写了一句“mask 参数必须为 PNG,透明区域表示要重新…

阅读更多 →
用C语言重写STM32启动文件:向量表、复位流程与链接脚本全解析 2026/10/1 22:57:09

用C语言重写STM32启动文件:向量表、复位流程与链接脚本全解析

“启动文件?那不是还存在于 flash 里的一小段汇编吗?”— — 这是不少嵌入式开发同学对 STM32 工程中startup_stm32f10x_hd.s的第一印象。我自己刚开始做初创项目时也是这个想法,直到有一次需要在一个无 IDE 侵入性较强的 GNU 工具链项目里重…

阅读更多 →
信捷XD3 PLC驱动六轴机器人:梯形图+C语言混合编程实战 2026/10/1 22:57:02

信捷XD3 PLC驱动六轴机器人:梯形图+C语言混合编程实战

1. 项目源起:为什么要把PLC和六轴机器人绑在一起 先交代一下背景。我手头这条产线原本用的是专用机器人控制器,调一次轨迹要拿示教器点半天,换产型的时候程序改动量大到怀疑人生。后来设备科压下来一个需求:把一台六轴机械臂并入现…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉