关于埃式筛法的极限优化
摘自https://blog.csdn.net/qq_43332305/article/details/82959066
关于素数的普通筛法想必大家都清楚。使用一个数组vis[n],从2遍历到n-1,每次碰到素数就把它的倍数剔除。这里有三种手段可以大大降低埃式筛法的时间复杂度:
先发埃式筛法模板,假设初始化vis所有成员为0,0代表是素数,1代表不是素数:
1 for(int i=2;i<=N;i++){ 2 if(!vis[i]){ 3 for(int j=2*i;j<=N;j+=i){ 4 vis[j]=1; 5 } 6 } 7 }
那么首先会想到一个问题,一个合数如果有因数,那么必定是成对存在,也就是筛子只用判断其中一个因数就可以了,比如15=3*5,在3的时候已经把15给筛掉了,何必去循环到5呢?于是优化如下,循环到根号n即可。
1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N 2 if(!vis[i]){ 3 for(int j=2*i;j<=N;j+=i){ 4 vis[j]=1; 5 } 6 } 7 }
接下来是第二重优化。第二层循环中不是从j=2i开始,每次增加一个i,即剔除i的所有倍数吗?试想一下,6是不是被2筛过了,此时碰到素数3又要筛一遍。而j从2i到i*i,即2倍到i倍的变化,在第一层循环中,2~i-1已经把他们的素数倍数筛完,所以结论如下:
第i个数只用筛从 i 乘 i 开始到n的每个数,而不用从 2 乘 i 开始
接下来优化代码:
1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N 2 if(!vis[i]){ 3 for(int j=i*i;j<=N;j+=i){//将2*i换成i*i 4 vis[j]=1; 5 } 6 } 7 }
第三重优化是一个很小的改动与优化,在第二重循环中,每次增加素数的1倍,但除了2以外素数都是奇数,那么奇数乘以偶数是偶数,偶数情况早已被2筛完,故每次增加2i倍.
1 for(int i=2;i*i<=N;i++){//将i<=N换成i*i<=N 2 if(!vis[i]){ 3 int mul;//倍数 4 i==2?mul=1:mul=2; 5 for(int j=i*i;j<=N;j=j+i*mul){//将2*i换成i*i 6 vis[j]=1; 7 } 8 } 9 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· Cursor预测程序员行业倒计时:CTO应做好50%裁员计划
· 当职场成战场:降职、阴谋与一场硬碰硬的抗争
· 用99元买的服务器搭一套CI/CD系统
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· Excel百万数据如何快速导入?