热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

cprime算法_「LeetCode算法精讲」计算小于n的质数数量(Python)

题目内容统计所有小于非负整数n的质数的数量。示例:输入:10输出:4解释:小于10的质数一共有4个,它们是2,3,5,7。来源:力扣(LeetCode)链接ÿ

题目内容

统计所有小于非负整数 n 的质数的数量。

示例:

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

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/count-primes/

著作权归领扣网络所有。

运行效率
1ce1d0f7849e5d5553f74443c6aa7758.png

LeetCode的Python执行用时随缘,只要时间复杂度没有明显差异,执行用时一般都在同一个量级,仅作参考意义。

解法一(完全暴力算法):

【思路】

首先,依据质数的定义,我们得到如下算法:

遍历所有小于目标值(n)且大于等于2的整数(c);并将这些整数(c)除以小于它们(c)且大于等于2的整数(i)来判断它们是不是质数。

这样的方法显示十分麻烦,每个数(c)都要除以c-1个数才能判断完成,此时的时间复杂度为O(n^2)。

 def countPrimes(self, n: int) -> int:     def is_primes(c):         """        判断c是否为质数        """         for i in range(2, n):             if c % i == 0:                 return False         return True ​     ans = 0     for j in range(2, n):         if is_primes(j):             ans += 1     return ans

解法二(不那么暴力的暴力算法):

【思路】

实际上,并不需要除以所有小于等于某整数(c)的整数来判断该整数(c)是否为质数。

因为,除该整数(c)的平方根外,其他所有可以整除该整数的两个数,都是一个小于平方根,一个大于平方根。例如:4

所以,当除到该整数(c)的平方根时,就已经可以将所有可能的情况枚举出来了。

由此,我们对算法优化如下:

 def countPrimes(self, n: int) -> int:     def is_primes(c):         """        判断c是否为质数        """         for i in range(2, int(pow(c, 0.5)) + 1):             if c % i == 0:                 return False         return True ​     ans = 0     for j in range(2, n):         if is_primes(j):             ans += 1     return ans

解法三(更不暴力的暴力算法):

【思路】

在解法二的基础上,我们发现其实如果已经除了2,那么再除4、6等偶数都是没有意义的。

因此,我们将算法优化为只除以之前已经发现的质数,得到如下算法:

 def countPrimes(self, n: int) -> int:     prime_list = []     for c in range(2, n):         for i in prime_list:             if c % i == 0:                 break         else:             prime_list.append(c)     return len(prime_list)

解法四(使用数组标记合数):

【思路】

既然后面的数我们已经是通过之前除以之前发现的质数来判断是否为质数,那没有其实已经没有必要再继续使用耗时更高除法了。

我们可以建立一个数组,用以标记各个数是否为质数;当我们每发现一个质数,就遍历将所有该质数的倍数标记为合数;这种方法叫做“厄拉多塞筛法”。

由此,我们得到如下算法,虽然时间复杂度为O(n^2),但是不用再使用除法了:

 def countPrimes(self, n: int) -> int:     num_list = [True for _ in range(n)] ​     for i in range(2, n):         if num_list[i]:  # 如果i为质数(不是任何质数的倍数)             for j in range(2 * i, n, i):                 num_list[j] = False ​     ans = 0     for i in range(2, n):         if num_list[i]:             ans += 1     return ans

解法五(优化解法四):

【思路】

因为我们在标记7的倍数时,14、21、28、35、42都已经被2、3、5标记过了,即7*7以下的7的倍数都已经被标记了,所以,我们只需要从7*7向上标记7的倍数就可以了。

因此,当我们判断到n平方根(即标记完小于等于n平方根的最大质数)后,就不用再判断和标记了。

由此,我们得到了如下算法:

 def countPrimes(self, n: int) -> int:     num_list = [True for _ in range(n)] ​     for i in range(2, int(pow(n, 0.5)) + 1):         if num_list[i]:  # 如果i为质数(不是任何质数的倍数)             for j in range(i * i, n, i):                 num_list[j] = False ​     ans = 0     for i in range(2, n):         if num_list[i]:             ans += 1     return ans

解法六(优化解法五):

【思路】

因为在Python中,Python的内置语句往往会比我们自己写的算法要更快,因此我们更多地使用一些Python的内置语句来优化算法。

同时,在生成各元素相同的列表时,“列表生成式”的运行速度比“列表乘以常数”的运行速度要慢很多,不再使用列表生成式。

 def countPrimes(self, n: int) -> int:     if n <2:         return 0 ​     num_list &#61; [True]*n     num_list[0], num_list[1] &#61; False, False ​     for i in range(2, int(pow(n, 0.5)) &#43; 1):         if num_list[i]:  # 如果i为质数(不是任何质数的倍数)             num_list[i * i::i] &#61; [False] * ((n - i * i - 1) // i &#43; 1)  # 因为要包含i*i所以需要&#43;1&#xff1b;因为n不在列表里&#xff0c;所以需要-1 ​     return sum(num_list)  # True就是1&#xff0c;False就是0&#xff0c;可以直接统计

至此&#xff0c;其实我们的算法已经优化得很好了&#xff0c;把那些枚举LeetCode测试数据的人忽略掉就行了。



推荐阅读
  • 本文介绍如何使用 Python 编写程序,检查给定列表中的元素是否形成交替峰值模式。我们将探讨两种不同的方法来实现这一目标,并提供详细的代码示例。 ... [详细]
  • 深入理解C++中的KMP算法:高效字符串匹配的利器
    本文详细介绍C++中实现KMP算法的方法,探讨其在字符串匹配问题上的优势。通过对比暴力匹配(BF)算法,展示KMP算法如何利用前缀表优化匹配过程,显著提升效率。 ... [详细]
  • 使用Numpy实现无外部库依赖的双线性插值图像缩放
    本文介绍如何仅使用Numpy库,通过双线性插值方法实现图像的高效缩放,避免了对OpenCV等图像处理库的依赖。文中详细解释了算法原理,并提供了完整的代码示例。 ... [详细]
  • 本文介绍如何使用 Python 将一个字符串按照指定的行和元素分隔符进行两次拆分,最终将字符串转换为矩阵形式。通过两种不同的方法实现这一功能:一种是使用循环与 split() 方法,另一种是利用列表推导式。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • python的交互模式怎么输出名文汉字[python常见问题]
    在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就进入到Python交互模式,它的提示符是>>>,此时我们可以使用print() ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
author-avatar
美煤MM就
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有