鱼C论坛

 找回密码
 立即注册
查看: 2545|回复: 7

[技术交流] 【C++板块提升计划】求质数的 N 种方法【原创】

[复制链接]
抢楼 抢楼 本帖为抢楼帖,欢迎抢楼! 
发表于 2023-1-8 15:02:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 zhangjinxuan 于 2023-1-9 14:28 编辑

第一类:枚举法
1. 暴力枚举因数
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool prime(int n) {
  4.         for (int i = 2; i < n; ++i) {
  5.                 if (n % i == 0) {
  6.                         return 0;
  7.                 }
  8.         }
  9.         return 1;
  10. }

  11. int main() {
  12.         int t, n;
  13.         scanf("%d", &t);
  14.         while (t--) {
  15.                 scanf("%d", &n);
  16.                 printf("%s\n", prime(n) ? "Yes" : "No");
  17.         }
  18. }
复制代码

通过枚举因数的方式找到质数
时间复杂度:O(n)
空间复杂度:O(1)
优点:适合初学者,空间复杂度小
缺点:时间复杂度高

2. 暴力枚举因数(优化版)
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool prime(int n) {
  4.         for (int i = 2; i * i <= n; ++i) {
  5.                 if (n % i == 0) {
  6.                         return 0;
  7.                 }
  8.         }
  9.         return 1;
  10. }

  11. int main() {
  12.         int t, n;
  13.         scanf("%d", &t);
  14.         while (t--) {
  15.                 scanf("%d", &n);
  16.                 printf("%s\n", prime(n) ? "Yes" : "No");
  17.         }
  18. }
复制代码

进行了优化,我们只用枚举到 n ^ 0.5
时间复杂度:O(sqrt(n))
空间复杂度:O(1)
优点:适合初学者,空间复杂度小,可以解决大部分问题了
缺点:时间复杂度还是高,需要一点数学功底

第二类:筛法
1. 埃氏筛
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool b[10000001];

  4. void init() {
  5.         b[1] = 1;
  6.         for (int i = 2; i <= 10000000; ++i) {
  7.                 if (!b[i]) {
  8.                         for (int j = i + i; j <= 10000000; j += i) {
  9.                                 b[j] = 1;
  10.                         }
  11.                 }
  12.         }
  13. }

  14. bool prime(int n) {
  15.         return b[n] ? 0 : 1;
  16. }

  17. int main() {
  18.         init();
  19.         int t, n;
  20.         scanf("%d", &t);
  21.         while (t--) {
  22.                 scanf("%d", &n);
  23.                 printf("%s\n", prime(n) ? "Yes" : "No");
  24.         }
  25. }
复制代码

筛法求素数,一开始就把素数筛出来,后面查询就很简单了,属于”一劳永逸“
时间复杂度:O(n log log n)
空间复杂度:O(n)
优点:时间复杂度低,可以满足大部分需求
缺点:不适合初学者,而且还容易被数据卡掉
2. 埃氏筛(优化版)
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool b[10000001];

  4. void init() {
  5.         b[1] = 1;
  6.         for (int i = 2; i * i <= 10000000; ++i) {
  7.                 if (!b[i]) {
  8.                         for (int j = i * i; j <= 10000000; j += i) {
  9.                                 b[j] = 1;
  10.                         }
  11.                 }
  12.         }
  13. }

  14. bool prime(int n) {
  15.         return b[n] ? 0 : 1;
  16. }

  17. int main() {
  18.         init();
  19.         int t, n;
  20.         scanf("%d", &t);
  21.         while (t--) {
  22.                 scanf("%d", &n);
  23.                 printf("%s\n", prime(n) ? "Yes" : "No");
  24.         }
  25. }
复制代码

进行了优化,一是 i 只要枚举到 sqrt(10000000),二是 j 可以从 i * i 开始枚举,这就是标准的埃氏筛了
时间复杂度:O(n log log n)
空间复杂度:O(n)
优点:时间复杂度低,可以满足大部分需求
缺点:不适合初学者,对于数学功底较高,还是容易被数据卡掉
3. 线性筛
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool b[10000001];
  4. int c[10000001], tot;

  5. void init() {
  6.         b[1] = 1;
  7.         for (int i = 2; i <= 10000000; ++i) {
  8.                 if (!b[i]) c[++tot] = i;
  9.                 for (int j = 1; i * c[j] <= 10000000 && j <= tot; ++j) {
  10.                         b[i * c[j]] = 1;
  11.                         if (c[j] % i == 0) break;
  12.                 }
  13.         }
  14. }

  15. bool prime(int n) {
  16.         return b[n] ? 0 : 1;
  17. }

  18. int main() {
  19.         init();
  20.         int t, n;
  21.         scanf("%d", &t);
  22.         while (t--) {
  23.                 scanf("%d", &n);
  24.                 printf("%s\n", prime(n) ? "Yes" : "No");
  25.         }
  26. }
复制代码

线性筛,线性筛,也就是它的时间复杂度是线性的,要知道,线性筛的灵魂就在于 if (c[j] % i == 0) break; 这一句
时间复杂度:O(n)
空间复杂度:O(n)
优点:时间复杂度低,再也不会被卡掉了
缺点:空间复杂度较高,不适合初学者,对于数学功底极高
第三类:表法
1.
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool b[10000001] = {0, 0, 1, 1, 0, 1, ...(省略约3千万字符) };

  4. bool prime(int n) {
  5.         return b[n];
  6. }

  7. int main() {
  8.         init();
  9.         int t, n;
  10.         scanf("%d", &t);
  11.         while (t--) {
  12.                 scanf("%d", &n);
  13.                 printf("%s\n", prime(n) ? "Yes" : "No");
  14.         }
  15. }
复制代码

打表,这个不言而喻,管你O(nloglogn),管你O(n),都比不过我的表!
时间复杂度:O(1)
空间复杂度:O(n)
优点:时间复杂度低,简单易懂,适合萌新
缺点:代码长,希望大家永远别写
2.
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. bool prime(long long n) {
  4.         if (n <= 1) return 0;
  5.         if (n <= 3) return 1;
  6.         if (n == 5) return 1;
  7.         /*此处省略约1垓个字符*/
  8. }

  9. int main() {
  10.         init();
  11.         int t, n;
  12.         scanf("%d", &t);
  13.         while (t--) {
  14.                 scanf("%d", &n);
  15.                 printf("%s\n", prime(n) ? "Yes" : "No");
  16.         }
  17. }
复制代码

这个更狠了……
时间复杂度:O(1)
空间复杂度:O(1)
优点:时间复杂度低,空间复杂度低,支持 long long,简单易懂,适合萌新和肝帝
缺点:保存这个代码需要 86EB 的存储空间

你还可以想到什么方法呢?欢迎回帖~

整理不易,喜欢别忘了评分

评分

参与人数 2荣誉 +7 鱼币 +8 贡献 +6 收起 理由
高山 + 2 + 3 + 3 鱼C有你更精彩^_^
柿子饼同学 + 5 + 5 + 3

查看全部评分

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-1-8 15:06:38 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-1-8 15:24:17 | 显示全部楼层
我有一个时间复杂度和空间复杂度都是O(1)的方法,但是代码有点长

评分

参与人数 1荣誉 +3 贡献 +1 收起 理由
高山 + 3 + 1 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-1-8 18:18:50 | 显示全部楼层
zhangjinxuan 发表于 2023-1-8 15:06
@tommyyu @柿子饼同学 @高山 求支持

我一般用 bitset

评分

参与人数 1荣誉 +3 贡献 +3 收起 理由
高山 + 3 + 3

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-1-8 18:34:25 | 显示全部楼层

要是多次询问就废了,而且long long好像也不行,试试 (1e9+7) * (1e9+7)?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-1-8 20:08:58 | 显示全部楼层
zhangjinxuan 发表于 2023-1-8 18:34
要是多次询问就废了,而且long long好像也不行,试试 (1e9+7) * (1e9+7)?

?
自己去查查 bitset 是啥
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-1-8 21:35:14 | 显示全部楼层
柿子饼同学 发表于 2023-1-8 20:08
?
自己去查查 bitset 是啥

我只知道它比正常变量快32倍,啊,我语法都没学完
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-1-9 07:47:03 | 显示全部楼层
zhangjinxuan 发表于 2023-1-8 21:35
我只知道它比正常变量快32倍,啊,我语法都没学完


可以多看看 STL , 里面很多有用的容器和函数
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-22 22:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表