质数计数问题求解

2024-06-03 23:44
文章标签 质数 求解 计数问题

本文主要是介绍质数计数问题求解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

质数计数问题求解

题目

leetcdoe204 计数质数:https://leetcode.cn/problems/count-primes

给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。

示例1:

  • 输入:n = 10

  • 输出:4

  • 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。

示例 2:

  • 输入:n = 0

  • 输出:0

示例 3:

  • 输入:n = 1

  • 输出:0

暴力解

直接判断小于 <n 中每个数是否为质数,是的话统计个数 +1,实现方法略过。

由于判断数字是否为质数时间复杂度为 O ( n ) O(\sqrt{n}) O(n ),所以整体时间复杂度 O ( n n ) O(n\sqrt{n}) O(nn ),直接超时。

埃氏筛

参考 leetcode 官方题解:https://leetcode.cn/problems/count-primes/solutions/507273/ji-shu-zhi-shu-by-leetcode-solution/

解题思路

枚举没有考虑到数与数的关联性,因此难以再继续优化时间复杂度。接下来我们介绍一个常见的算法,该算法由希腊数学家厄拉多塞(Eratosthenes)提出,称为厄拉多塞筛法,简称埃氏筛

我们考虑这样一个事实:如果 x 是质数,那么大于 x 的 x 的倍数 2x,3x,4x,… 一定不是质数,因此我们可以从这里入手。

我们设 isPrime[i] 表示数 i 是不是质数,如果是质数则为 1,否则为 0。从小到大遍历每个数,如果这个数为质数,则将其所有的倍数都标记为合数(除了该质数本身),即0,这样在运行结束的时候我们即能知道质数的个数。

这种方法的正确性是比较显然的:这种方法显然不会将质数标记成合数;另一方面,当从小到大遍历到数x 时,倘若它是合数,则它一定是某个小于 x 的质数 y 的整数倍,故根据此方法的步骤,我们在遍历到 y 时,就一定会在此时将 x 标记为 isPrime[x] = 0 。因此,这种方法也不会将合数标记为质数。

当然这里还可以继续优化,对于一个质数 x,如果按上文说的我们从 2x 开始标记其实是冗余的,应该直接从 x*x 开始标记,因为 2x,3x,4x,… 这些数一定在 x 之前就被其他数的倍数标记过了,例如 2 的所有倍数,3 的所有倍数等。

举个例子:

假设需要判断 n=17 的埃氏筛:x=2,需要划掉 >= 2^2 的2的倍数,即 4,6,8,10,12,14,16x=3,需要划掉 >= 3^2 的3 的倍数,即 9,12,15(12已经被2划掉过,这里产生了冗余过程)x=4,之前已经被2划掉了,说明是合数,跳过x=5,需要划掉 >= 5^2 的5 的倍数,但是 5^2 = 25 > 17,什么也不用干后面的也类似,要么已经被划掉了,要么 x^2 > 17。因此最后,留下了 2,3,5,7,11,13,17

image

复杂度
  • 时间复杂度: O ( n l o g l o g n ) O(nloglogn) O(nloglogn),这里就不严格证明了。

  • 空间复杂度: O ( n ) O(n) O(n)。我们需要 O ( n ) O(n) O(n) 的空间记录每个数是否为质数。

实现代码

标准实现:

  • Python实现
    def countPrimes(n: int) -> int:if n == 0 or n == 1:return 0prime_arr = [True] * nprime_arr[0] = Falseprime_arr[1] = Falsecur = 2while cur * cur <= n:if prime_arr[cur]:num = cur * curwhile num < n:prime_arr[num] = Falsenum += curcur += 1result = 0for is_prime in prime_arr:if is_prime:result += 1return result
  • Java实现
public int countPrimes(int n) {int[] isPrime = new int[n];Arrays.fill(isPrime, 1);int ans = 0;for (int i = 2; i < n; ++i) {if (isPrime[i] == 1) {ans += 1;if ((long) i * i < n) {for (int j = i * i; j < n; j += i) {isPrime[j] = 0;}}}}return ans;
}

由于除了 2 以外的所有偶数都不是质数,那么我们可以对这一部分数据进行剪枝处理

  • Python实现
    def countPrimes(n: int) -> int:if n < 3:return 0# f如果j确定是合数, 将 f[j] 设置为 Truef = [False] * n# 所有偶数都不要, 剩余的个数count = n // 2cur = 3while cur * cur < n:if not f[cur]:# cur 的 倍数中小于 cur * cur 的已经由其他数添加了# cur 只用考虑奇数for j in range(cur * cur, n, 2 * cur):if not f[j]:count -= 1f[j] = Truecur += 2return count
  • Java实现
public int countPrimes(int n) {if (n < 3) {return 0;}boolean[] f = new boolean[n];int count = n / 2;for (int i = 3; i * i < n; i += 2) {if (f[i]) {continue;}for (int j = i * i; j < n; j += 2 * i) {if (!f[j]) {--count;f[j] = true;}}}return count;
}

埃氏筛拓展

Euler Project 10

先看一道类似的题目:求出 200万 以内所有质数之和

参考自:https://www.zhihu.com/question/29580448/answer/45218281

这个算法原题来自 https://projecteuler.net/problem=10

image

在论坛中由 Lucy_Hedgehog 给出具体计算流程。

整体思路

这里以Euler Project 10 中的解,说明计算过程。(即求质数和,而不是质数个数)。

定义 S ( v , p ) S(v,p) S(v,p) 为2…v 所有整数中,在上面的埃氏筛中,外层循环筛完p 时,仍然幸存的数的和

因此这些数:

  • 要不本身是素数

  • 要不其最小的素因子也大于p

因此我们需要求的是: S ( n , ⌊ n ⌋ ) S(n,⌊\sqrt{n}⌋) S(n,n ⌋),n=200w

为了计算 S ( v , p ) S(v,p) S(v,p),先考虑几个特殊情况

1) p ≤ 1 p \le 1 p1时所有数都还没有被筛掉,所以 S ( v , p ) = ∑ i = 2 v i = ( 2 + v ) ( v − 1 ) 2 S(v,p)=\sum_{i=2}^{v}{i}=\frac{(2+v)(v-1)}{2} S(v,p)=i=2vi=2(2+v)(v1)

2)p 不是素数。因为筛法中早已被别的数筛掉,所以在这步什么都不会做,所以此时 S ( v , p ) = S ( v , p − 1 ) S(v,p)=S(v,p-1) S(v,p)=S(v,p1)

3)p是素数,但是 v < p 2 v<p^2 v<p2。因为每个合数都一定有一个不超过其平方根的素因子,如果筛到 p时还没筛掉一个数,那么筛到 p−1 时这个数也还在。所以此时也有 S ( v , p ) = S ( v , p − 1 ) S(v,p)=S(v,p-1) S(v,p)=S(v,p1)

举个例子

如果 v = 30,p=7,埃氏法中以 7 开头筛选的数字中,最小的为 7 * 7 = 49 > 30,不会划掉任何数字
因此此时和外层筛选到 6 相比,没有做任何操作。

现在考虑最后一种稍微麻烦些的情况:p 是素数,且 p 2 ≤ v p^2 \le v p2v

此时,我们要用素数 p 去筛掉剩下的那些数中 p 的倍数。注意到现在还剩下的合数都没有小于 p 的素因子。因此有:

S ( v , p ) = S ( v , p − 1 ) − ∑ k ,其中, 2 ≤ k ≤ v ,且 k 最小素因子为 p S(v,p)=S(v,p-1)-\sum{k},其中,2\le k\le v,且k最小素因子为p S(v,p)=S(v,p1)k,其中,2kv,且k最小素因子为p

后面那项中提取公共因子 p,有:

S ( v , p ) = S ( v , p − 1 ) − p × ∑ k p ,其中, 2 ≤ k ≤ v

这篇关于质数计数问题求解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1028454

相关文章

2024 年高教社杯全国大学生数学建模竞赛题目——2024 年高教社杯全国大学生数学建模竞赛题目的求解

2024 年高教社杯全国大学生数学建模竞赛题目 (请先阅读“ 全国大学生数学建模竞赛论文格式规范 ”) 2024 年高教社杯全国大学生数学建模竞赛题目 随着城市化进程的加快、机动车的快速普及, 以及人们活动范围的不断扩大,城市道 路交通拥堵问题日渐严重,即使在一些非中心城市,道路交通拥堵问题也成为影响地方经 济发展和百姓幸福感的一个“痛点”,是相关部门的棘手难题之一。 考虑一个拥有知名景区

基于SA模拟退火算法的多车辆TSP问题求解matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述        基于SA模拟退火算法的多车辆TSP问题求解matlab仿真,三个车辆分别搜索其对应的最短路径,仿真后得到路线规划图和SA收敛曲线。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 (完整程序运行后无水印)

OpenGL/GLUT实践:流体模拟——数值解法求解Navier-Stokes方程模拟二维流体(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub:A-UESTCer-s-Code 文章目录 1 实现效果2 实现过程2.1 流体模拟实现2.1.1 网格结构2.1.2 数据结构2.1.3 程序结构1) 更新速度场2) 更新密度值 2.1.4 实现效果 2.2 颜色设置2.2.1 颜色绘制2.2.2 颜色交互2.2.3 实现效果 2.3 障碍设置2.3.1 障碍定义2.3.2 障碍边界条件判定2.3.3 障碍实现2.3.

JD 1147:Jugs(一种用最少步骤求解的方法)

OJ题目:click here~~ 题目分析:九度上这道没有要求最少步数,只要得到最后结果即可AC , bfs , dfs都行。最少步骤的方法肯定也能AC啦,分析如下。 输入的三个数:a,b,n;> 由题不定方程ax+by=n必定有解> 如果b=n,则fill B即可,否则用试探法求出这样的两组解(a1,b1)及(a2,b2),其中a1 >0,b1<0;a1是满足方程的最小正整数;a2

js算法题,给任意一个偶数,找出他的所有的质数因子

/*给任意一个偶数,找出他的所有的质数因子*/ function primeFactor(n){     var factors=[],            divistor=2;     if(typeof n !=='number'||!Number.isInteger(n)){          return 0;     }; //如果不是偶数返回0,如果是0,返回0

【2024全国大学生数学建模竞赛】B题 模型建立与求解(含代码与论文)

目录 1问题重述1.1问题背景1.2研究意义1.3具体问题 2总体分析3模型假设4符号说明(等四问全部更新完再写)5模型的建立与求解5.1问题一模型的建立与求解5.1.1问题的具体分析5.1.2模型的准备 目前B题第一问的详细求解过程以及对应论文部分已经完成! - 晚上7-8点之前第二问完成 - 明天中文之前全部写完 按照提交论文的格式进行撰写!完整版请看文章最后!

Java 快速求解x的x次幂结果为10

1.问题描述 如果x的x次幂结果为10(如图所示),你能计算出x的近似值吗? 显然,这个值是介于2和3之间的一个数字。 可以使用牛顿迭代公式进行求解,因为是逼近算法可以大大减少运算次数 public static void main(String[] args) {int i = 0;double x1 = 2.5;while (true) {i++;//x^x - 10 = 0//这一步

最值求解 | 管理类联考数学专项

日期内容2024.9.5新建2024.9.6曦曦求最值完结 实数求最值至少至多抽屉原理工程问题线性规划一次性绝对值求最值 参考: b站跟着曦曦老师玩转【最值】

2024数学建模国赛A题详细思路:基于空间几何运动学和优化模型matlab求解

2024数学建模国赛A题“板凳龙”闹元宵 2024高教社杯数学建模竞赛A题B题C题D题E题完整成品文章和全部问题的解题代码完整版本更新如下:https://www.yuque.com/u42168770/qv6z0d/rytbc1nelty1mu4o % 定义常量L_head = 3.41; % 龙头长度(米)L_body = 2.20; % 龙身长度(米)spiral_pitch =

清华MEM作业-利用管理运筹学的分析工具slover求解最优解的实现 及 通过使用文件或者套节字来识别进程的fuser命令

一、清华MEM作业-利用管理运筹学的分析工具slover求解最优解的实现         最近又接触了一些线性求解的问题,以前主要都是在高中数学里接触到,都是使用笔算,最后通过一些函数式得出最小或者最大值,最近的研究生学业上接触到了一个Excel solver分析工具,对这种线性求最优解的问题感觉使用起来真是得心应手。在使用这个工具前,EXCEL里需要先装上solver工具,装起来很也简单,网上