质数计数问题求解

质数计数问题求解

题目

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 ),直接超时。

Temp

埃氏筛

参考 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,16

x=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(nloglogn),这里就不严格证明了。

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

实现代码

标准实现:

    def countPrimes(n: int) -> int:
        if n == 0 or n == 1:
            return 0
        prime_arr = [True] * n
        prime_arr[0] = False
        prime_arr[1] = False
        cur = 2
        while cur * cur <= n:
            if prime_arr[cur]:
                num = cur * cur
                while num < n:
                    prime_arr[num] = False
                    num += cur
            cur += 1
        result = 0
        for is_prime in prime_arr:
            if is_prime:
                result += 1
        return result

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

    def countPrimes(n: int) -> int:
        if n < 3:
            return 0
        # f如果j确定是合数, 将 f[j] 设置为 True
        f = [False] * n
        # 所有偶数都不要, 剩余的个数
        count = n // 2
        cur = 3
        while 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 -= 1
                        f[j] = True
            cur += 2
        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 ,且 k 最小素因子为 p S(v,p)=S(v,p-1)-p×\sum{\frac{k}{p}},其中,2\le k\le v,且k最小素因子为p S(v,p)=S(v,p1)p×pk,其中,2kv,且k最小素因子为p

因为 p 整除 k,稍微变形一下,令 t &#

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/675444.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go 线程同步

一、介绍 通常在 Go 语言中有两种方法可以用来做线程同步 sync.Cond channel channel 的很好理解&#xff0c;当我们从一个 channel 中接收数据的时候&#xff0c;如果里面没有数据&#xff0c;那我们直接就阻塞在那里了。 在 Go 语言中&#xff0c;如果你尝试在已经持有某…

【设计模式】JAVA Design Patterns——Monitor(监视器模式)

&#x1f50d;目的 主要目的是为多个线程或进程提供一种结构化和受控的方式来安全地访问和操作共享资源&#xff0c;例如变量、数据结构或代码的关键部分&#xff0c;而不会导致冲突或竞争条件。 &#x1f50d;解释 通俗描述 监视器模式用于强制对数据进行单线程访问。 一次只允…

基于java的CRM客户关系管理系统(六)

目录 5.3 表现层设计 5.3.1 模型层&#xff08;M&#xff09; 5.3.2 视图层&#xff08;V&#xff09; 5.3.3 控制层&#xff08;C&#xff09; 5.4 系统主要功能模块的实现 5.4.1 登录功能的实现 5.4.2 客户管理的实现 5.5 本章小结 参考文献 前面内容请移步 基于java…

基本元器件 - 电感与磁珠

电感 电感的选型 体积大小电感值所在工作频率开关频率下的电感值为实际需要的电感值线圈的直流阻抗&#xff08;DCR&#xff09;越小越好工作电流应降额至额定饱和电流的 0.7 倍以下&#xff0c;额定 rms 电流&#xff1b;交流阻抗&#xff08;ESR&#xff09;越小越好&#…

10 款在线剽窃检查的 [免费工具]

剽窃或抄袭他人文章而不注明出处&#xff0c;几乎在所有领域都被认为是有害的。然而&#xff0c;学术界最痛恨这种行为。抄袭是对学术诚信的最大威胁。这就是为什么每个教育机构总是希望学生提交无抄袭的作业。 然而&#xff0c;有时学生无意中剽窃了他人的作业&#xff0c;直…

【软件开发】Java学习路线

本路径视频教程均来自尚硅谷B站视频&#xff0c;Java学习课程我已经收藏在一个文件夹下&#xff0c;B站文件夹同时会收藏其他Java视频&#xff0c;感谢关注。指路&#xff1a;https://www.bilibili.com/medialist/detail/ml3113981545 2024Java学习路线&#xff08;快速版&…

命名空间,缺省参数和函数重载

前言&#xff1a;本文章主要介绍一些C中的小语法。 目录 命名空间 namespace的使用 访问全局变量 namespace可以嵌套 不同文件中定义的同名的命名空间可以合并进一个命名空间&#xff0c;并且其中不可以有同名的变量 C中的输入和输出 缺省参数&#xff08;默认参数&#…

超越Devin!姚班带队,他们创大模型编程新世界纪录

超越Devin&#xff01;SWEBench排行榜上迎来了新玩家—— StarShip CodeGen Agent&#xff0c;姚班带队初创公司OpenCSG出品&#xff0c;以23.67%的成绩获得全球第二名的成绩。 同时创造了非GPT-4o基模的最高纪录&#xff08;SOTA&#xff09;。 我们都知道&#xff0c;SWEBe…

for深入学习

目录 练习&#xff1a; 例1&#xff1a; 求解0-100中整除3的数有哪些 例2&#xff1a; 求0-100中含数字9个个数 作业&#xff1a; 练习&#xff1a; 例1&#xff1a; 求解0-100中整除3的数有哪些 代码&#xff1a; #include<stdio.h> int main() {printf("整…

JAVAEE之网络初识_协议、TCP/IP网络模型、封装、分用

前言 在这一节我们简单介绍一下网络的发展 一、通信网络基础 网络互连的目的是进行网络通信&#xff0c;也即是网络数据传输&#xff0c;更具体一点&#xff0c;是网络主机中的不同进程间&#xff0c;基于网络传输数据。那么&#xff0c;在组建的网络中&#xff0c;如何判断到…

深入理解计算机系统 第三版 中文版 图5-27 p371 错漏

中文版 英文版 对照 可以看出错漏 这本书中文版很多错漏,可以配合英文版查正,不过英文版也很多错漏,所以不用太相信书本.要根据自己的理解来.

TDengine为物联网而生的大数据平台

TDengine为物联网而生的大数据平台 物联网背景 技术支撑 应用落地 未来趋势

【动手学深度学习】softmax回归从零开始实现的研究详情

目录 &#x1f30a;1. 研究目的 &#x1f30a;2. 研究准备 &#x1f30a;3. 研究内容 &#x1f30d;3.1 softmax回归的从零开始实现 &#x1f30d;3.2 基础练习 &#x1f30a;4. 研究体会 &#x1f30a;1. 研究目的 理解softmax回归的原理和基本实现方式&#xff1b;学习…

算法金 | 再见,支持向量机 SVM!

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 一、SVM概述 定义与基本概念 支持向量机&#xff08;SVM&#xff09;是一种监督学习模型&#xff0c;用于解决分类和回归问题。它的核…

Streamsets-JDBC模式offset变化逻辑和如何向下传递offset

Streamsets的版本为3.16.0 离线版 offset在jdbc模式中起到非常关键的作用&#xff0c;是滚动查询的基础&#xff0c;offset的准确直接影响数据同步的质量。 本文主要分享一下JDBC Query Consumer中的offset&#xff0c;包括变化逻辑、存储方式、处理器如何获取到最新的offset。…

如何在QGIS中加载MapBox图源

在设计行业中需要多风格地图的调用&#xff0c;不管是规划、建筑设计还是景观&#xff0c;分析图的工作量都大&#xff0c;有好的底图&#xff0c;会事半功倍。 针对不同项目&#xff0c;会选择不同配色的底图&#xff0c;以便让设计内容中的呈现足够清晰。 这里就来分享一个…

如何在自己的电脑上添加静态路由

1.任务栏搜索powershell 选择以管理员身份运行 2.输入 route add -p (永久) 目的网络地址例如192.168.10.0 mask 255.255.255.0&#xff08;子网掩码&#xff09;192.168.20.1&#xff08;下一跳地址&#xff09;。回车即可生效

238.除以自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。 题目数据保证数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度内完…

网络编程(六)

网络编程&#xff08;六&#xff09; 广播&组播广播步骤 组播步骤 广播&组播 广播 是一种基于1发送多接收的模型 &#xff08;发送方和接收方&#xff09; 广播是在局域网内实现的&#xff08;发送到广播地址上的消息是会被局域网内同网段的所有主机进行接收&#xf…

[Redis]Set类型

集合类型也是保存多个字符串类型的元素的&#xff0c;但和列表类型不同的是&#xff0c;集合中 1&#xff09;元素之间是无序的 2&#xff09;元素不允许重复 一个集合中最多可以存储2^32-1个元素。 Redis 除了支持集合内的增删查改操作&#xff0c;同时还支持多个集合取交…