每日一题——Python实现PAT甲级1015 Reversible Primes(举一反三+思想解读+逐步优化)

news2024/11/29 6:34:44


一个认为一切根源都是“自己不够强”的INTJ

个人主页:用哲学编程-CSDN博客
专栏:每日一题——举一反三
Python编程学习
Python内置函数

Python-3.12.0文档解读

目录

我的写法

is_prime函数分析:

decimal_to_base函数分析:

主循环分析:

我要更强

is_prime函数优化

decimal_to_base函数优化

完整代码及注释

优化解释

总结

哲学和编程思想

举一反三


题目链接

我的写法

# 定义函数is_prime用来检测一个数n是否为质数
def is_prime(n):
    # 如果n小于等于1,则它不是质数
    if n <= 1:
        return False
    # 如果n小于等于3,则它是质数
    if n <= 3:
        return True
    # 如果n能被2或3整除,则它不是质数
    if n % 2 == 0 or n % 3 == 0:
        return False
    # 初始化变量i为5
    i = 5
    # 循环,检测5及以上的数是否能整除n
    while i * i <= n:
        # 如果n能被i或i+2整除,则它不是质数
        if n % i == 0 or n % (i + 2) == 0:
            return False
        # 将i增加6后继续循环(6k±1的优化)
        i += 6
    # 如果上述条件都不满足,则n是质数
    return True

# 定义函数decimal_to_base,将十进制数转换为给定的base进制
def decimal_to_base(decimal_num, base):
    # 如果base不在2到36之间,则返回错误信息
    if base < 2 or base > 36:
        return "Base must be between 2 and 36."
    # 定义一个字符串包含了可能在进制转换中用到的所有字符
    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    # 如果decimal_num小于base,直接返回对应的字符
    if decimal_num < base:
        return digits[decimal_num]
    # 否则进行递归调用,计算decimal_num除以base的商,并将余数对应的字符附加在后面
    else:
        return decimal_to_base(decimal_num // base, base) + digits[decimal_num % base]

# 主循环
while True:
    # 通过输入接收一行,然后分割字符串
    tmp=input().split()
    # 如果输入的长度小于2(即没有输入两个值),则退出循环
    if len(tmp)<2:
        break
    # 将输入的两个值转换为整数
    N,base=map(int,tmp)
    # 检查N是否为质数,以及N转换为指定进制后,翻转字符串并转换回十进制是否也为质数
    if is_prime(N) and is_prime(int(decimal_to_base(N,base)[::-1],base)):
        # 如果都是质数,则输出"Yes"
        print("Yes")
    else:
        # 否则输出"No"
        print("No")

这段代码包含两个主要的功能:一个是判断给定的整数是否为质数(is_prime函数),另一个是将十进制数转换为给定基数的表达形式(decimal_to_base函数)。最后,这两个功能在一个主循环中结合起来,以判断一个数及其在给定基数下的反转是否都是质数。

is_prime函数分析:

  • 正确性:
    • 此函数正确地实现了质数的判断,首先排除了不可能是质数的情况:小于等于1以及能够被2或3整除的数。其次利用了一个数学事实,即如果一个数n不是质数,那么它必定有一个因数小于或等于sqrt(n)。所以函数只检查到i*i <= n即可。
    • 6k±1规则被用来减少需要检查的可能因子,因为所有质数(除了2和3)都能表示成6k±1的形式。
  • 时间复杂度:
    • 在最坏的情况下(n是一个质数或者只能被另一个质数整除),这个算法的时间复杂度是O(sqrt(n)),因为它最多需要检查sqrt(n)个数字。
  • 空间复杂度:
  • 该函数使用了常数空间,除了输入值n和循环变量i之外,没有使用额外的存储空间。

decimal_to_base函数分析:

  • 正确性:
    • 函数正确地实现了基数转换,使用了递归方法。它也考虑了边界情况,即基数需要在2到36之间。
  • 时间复杂度:
    • 这个函数的时间复杂度是O(log_base(n)),因为每次递归调用都将数字n除以基数base。
  • 空间复杂度:
  • 由于使用了递归,空间复杂度也是O(log_base(n))。每次递归调用都会在调用栈中添加一层,直到达到基准情况。

主循环分析:

  • 主循环不断从用户那里接收输入,直到接收到的输入长度小于2。对于每一对输入,它会判断N是否为质数,以及N转换为指定进制后翻转字符串再转换回十进制是否也为质数。
  • 时间复杂度:
    • 主循环的时间复杂度依赖于输入的数N和基数base。质数检测有O(sqrt(N))的时间复杂度,而基数转换和反转字符串有O(log_base(N))的时间复杂度。
    • 质数检测会被执行两次,一次对原始数N,一次对翻转后的数。如果这两个数的大小相近,总的时间复杂度大约是O(sqrt(N) + log_base(N))。
  • 空间复杂度:
  • 主循环使用的空间主要取决于is_prime和decimal_to_base函数的空间复杂度,分别是O(1)和O(log_base(N))。因此,主循环的总空间复杂度大约是O(log_base(N))。

总的来说,该代码是高效和有效的,特别是在判断质数和基数转换方面使用了一些优化的方法。不过,递归可能在非常大的数字和/或基数非常高时导致栈溢出,所以在这种情况下可能需要迭代的方法来代替递归实现基数转换。


我要更强

针对前述代码,我们可以考虑一些优化策略,以提高算法的效率和减少内存使用。优化主要集中在两个方面:is_prime函数和decimal_to_base函数的改进。

is_prime函数优化

对于is_prime函数,我们已经使用了6k±1规则来减少必要的检查次数,这是一个很好的优化。进一步的优化可能不会显著减少时间复杂度,因为它本质上已经是O(sqrt(n)),这是检查质数的较快方法之一。

decimal_to_base函数优化

对于decimal_to_base函数,我们可以避免递归以减少空间复杂度。通过使用循环而不是递归,我们可以将空间复杂度降低到O(1)。

完整代码及注释

def is_prime(n):
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

def decimal_to_base(decimal_num, base):
    if base < 2 or base > 36:
        return "Base must be between 2 and 36."
    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    result = ""
    while decimal_num > 0:
        result = digits[decimal_num % base] + result
        decimal_num //= base
    return result or "0"

while True:
    tmp = input().split()
    if len(tmp) < 2:
        break
    N, base = map(int, tmp)
    if is_prime(N) and is_prime(int(decimal_to_base(N, base)[::-1], base)):
        print("Yes")
    else:
        print("No")

优化解释

  • is_prime函数保持不变,因为其时间复杂度已经是针对其操作相对较优的了。
  • decimal_to_base函数已改为使用循环而非递归。这种方法相比递归,减少了额外的函数调用开销和调用栈空间使用,从而将空间复杂度降低到O(1)。循环简单地将数字按基数转换,并每次迭代将余数添加到结果字符串的前面,达到了逆序的效果。

总结

这些优化帮助减少了内存使用(尤其是在decimal_to_base函数中避免了递归),而is_prime函数的优化主要集中在减少不必要的迭代上。然而,值得注意的是,在某些情况下,优化可能带来的性能提升是有限的,尤其是当输入值非常大时。此外,代码的可读性和维护性也是在进行优化时需要考虑的因素之一。


哲学和编程思想

在优化上述代码的过程中,我们实际上应用了几个编程和软件设计的哲学和思想:

  1. KISS原则(Keep It Simple, Stupid): 此原则主张尽可能保持简单,避免不必要的复杂性。在优化decimal_to_base函数时,我们采用了一个简单的循环代替了递归,这使得函数实现更为直观且易于理解。
  2. DRY原则(Don't Repeat Yourself): 这个原则鼓励减少重复,无论是数据还是逻辑。虽然在这里的优化中没有直接体现,但保持函数的单一职责(如is_prime只检查质数)和避免在代码中重复相同的逻辑是这个原则的体现。
  3. 分治思想: 分治方法是一种将问题分解为更小部分来解决,然后合并结果以获得最终解决方案的方法。在原始代码中,decimal_to_base通过递归将大问题分解为小问题。优化后,虽然不再使用递归,但仍然通过循环逐步构建最终结果,可以看作是分治思想的一种变形应用。
  4. 时间和空间权衡: 在计算机科学中,经常需要在时间复杂度和空间复杂度之间做出权衡。例如,在递归和迭代之间选择,就需要权衡它们在时间和空间上的消耗。在这里,我们优化decimal_to_base函数,将空间复杂度降低到O(1),而保持时间复杂度不变,体现了对资源利用的权衡。
  5. 最小惊讶原则: 这个原则表明代码应该如何预期般行事,避免混淆使用者。优化后的代码更加直白和易于理解,符合这一原则。
  6. 可维护性和可读性: 优化代码的另一个考虑是确保代码的可维护性和可读性。在上述代码中,尽管我们进行了优化,但仍然保持了代码的清晰性和可读性,使得未来的维护更加容易。
  7. 渐进增强: 这是一种逐步改进代码的方法,首先实现一个简单的版本,然后逐渐增加优化和改进。例如,我们首先定义了is_prime和decimal_to_base的基本版本,然后在后续版本中对其进行了优化。
  8. 代码重构: 代码重构是改进现有代码结构而不改变其外部行为的过程。在优化decimal_to_base函数中,我们进行了重构,通过替换递归为迭代,来优化性能而不改变函数的功能。

这些哲学和思想都是编程实践中常常被采用的,目的是为了写出高效、易于维护和理解的代码。实现这些通常需要在代码的性能和其他因素(如可读性、可维护性)之间进行仔细的权衡。


举一反三

采用这些哲学和编程思想,以下是一些通用的编程技巧和最佳实践,你可以将它们应用于各种编程任务中:

  1. 追求简洁:
    • 在设计算法和编写代码时,始终问自己是否可以进一步简化。避免过度工程化,尽量不要增加不必要的复杂度。
  2. 避免重复:
    • 注意代码中的重复模式。使用函数、类或模块来封装重复的代码,以提高复用性。
  3. 逐步开发:
    • 避免一开始就尝试编写完整的复杂系统。从一个基本的、可以工作的版本开始,然后逐渐添加特性和改进。
  4. 注重可读性:
    • 书写清晰的代码,这不仅有助于别人理解,也有助于未来的你回顾和维护代码。使用有意义的变量名、保持一致的代码风格、添加注释和文档。
  5. 重构:
    • 定期审视和重构你的代码。随着项目的进行和需求的变化,始终保持代码整洁和组织良好。
  6. 性能和资源的权衡:
    • 根据应用场景,确定何时应优先考虑时间效率,何时应优先考虑空间效率。有时快速的代码需要消耗更多内存,有时节省内存的代码可能不那么快。
  7. 模块化和解耦:
    • 设计代码时,使各个部分之间的耦合最小化。每个模块或函数应负责一组明确的任务,这样可以单独测试和优化。
  8. 代码的可测试性:
    • 编写代码时考虑测试。如果代码难以测试,它可能也难以维护。使用单元测试来验证每个部分的功能。
  9. 持续学习:
    • 不断学习新的技术和方法。编程是一个快速发展的领域,而且不同的问题可能需要不同的解决策略。
  10. 错误的预期和处理:
  • 设计代码时要考虑到错误的可能性。使用异常处理、断言和合适的错误处理来提高代码的健壮性。

感谢阅读。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Segment Anything

参考&#xff1a;【图像分割】Segment Anything&#xff08;Meta AI&#xff09;论文解读-CSDN博客 背景 提示分割任务&#xff1a;在给定任何分割提示下返回一个有效的分割掩码目标&#xff1a;开发一个可提示的图像分割的基础模型&#xff0c;在一个广泛的数据集上预训练&a…

【网络安全的神秘世界】在win11搭建pikachu靶场

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 下载pikachu压缩包 https://github.com/zhuifengshaonianhanlu/pikachu 下载好的pikachu放在phpstudy_pro/www目录下 创建pikachu数据库 打开phpstudy软件…

数据结构--二叉树(二)

链式二叉树 链式二叉树是链式树集合中的一种&#xff0c;该树的每个根节点最多只有两个孩子节点&#xff0c;我们一般用左右孩子来称呼&#xff0c;在初学链式二叉树时&#xff0c;由于大家对链式二叉树的结构掌握还不够深入&#xff0c;为了降低本章的学习难度及成本&#xff…

大模型多轮问答的两种方式

前言 大模型的多轮问答难点就是在于如何精确识别用户最新的提问的真实意图&#xff0c;而在常见的使用大模型进行多轮对话方式中&#xff0c;我接触到的只有两种方式&#xff1a; 一种是简单地直接使用 user 和 assistant 两个角色将一问一答的会话内容喂给大模型&#xff0c…

u盘内容无故消失了是什么原因?u盘部分内容无故消失了怎么恢复

在数字化时代&#xff0c;U盘作为便携存储设备&#xff0c;承载着许多重要的数据。然而&#xff0c;有时我们可能会遭遇U盘部分内容无故消失的情况&#xff0c;这无疑给我们的工作和生活带来了不小的困扰。本文将为您解析U盘内容消失的可能原因&#xff0c;并分享几招实用的数据…

[经验] 场效应管是如何发挥作用的 #知识分享#学习方法#职场发展

场效应管是如何发挥作用的 在现代电子技术领域&#xff0c;场效应管&#xff08;MOSFET&#xff09;是一种重要的半导体元器件。它的作用非常广泛&#xff0c;例如在集成电路中扮演着关键的角色。在本文中&#xff0c;我们将详细探讨场效应管的作用及其在实际应用中的意义。 简…

[职场] 社保和商业保险有什么区别?可以只买商保不买社保吗? #微信#经验分享#媒体

社保和商业保险有什么区别&#xff1f;可以只买商保不买社保吗&#xff1f; 我们在提到社保和商业保险时&#xff0c;经常会听到这样一句话&#xff1a;“社保是基础&#xff0c;商保是补充。” 为什么会这样说呢&#xff1f;社保和商保有什么区别呢&#xff1f;今天&#xf…

AutoCAD Mechanical机械版专业的计算机辅助设计软件安装包下载安装!

AutoCAD机械版作为一款专业的计算机辅助设计软件&#xff0c;不仅具备卓越的二维绘图功能&#xff0c;更是拥有令人瞩目的3D建模工具&#xff0c;为机械设计师们提供了前所未有的创作空间。 在AutoCAD机械版的3D建模环境中&#xff0c;用户可以借助一系列简洁明了的命令&#…

SMS - 基于阿里云实现手机短信验证码登录(无需备案,非测试)

目录 SMS 环境调试 从阿里云云市场中购买第三方短信服务 调试短信验证码功能 实战开发 封装组件 对外接口 调用演示 SMS 环境调试 从阿里云云市场中购买第三方短信服务 a&#xff09;进入阿里云首页&#xff0c;然后从云市场中找到 “短信” &#xff08;一定要从 云…

SpringBoot高手之路-springboot原理篇

配置文件优先级 SpringBoot原理篇-多环境配置

JFinal学习07 控制器——接收数据之getBean()和getModel()

JFinal学习07 控制器——接收数据之getBean()和getModel() 视频来源https://www.bilibili.com/video/BV1Bt411H7J9/?spm_id_from333.337.search-card.all.click 文章目录 JFinal学习07 控制器——接收数据之getBean()和getModel()一、接收数据的类型二、getBean()和getModel()…

Pytorch手把手实作-Generative Adversarial Network (GAN)

文章目录 一、说明二、GAN的介绍三、生成器和鉴别器四、代码实现 一、说明 前言废话免了&#xff0c;会进来看文章内容的只有四种人&#xff1a;1. 只想知道皮毛&#xff0c;GAN在干什么的 2. 想知道细节怎么把GAN训练起来&#xff1b;3. 收藏在收藏夹或是书签当作有看过了&am…

HTTP协议分析实验:通过一次下载任务抓包分析

HTTP协议分析 问&#xff1a;HTTP是干啥用的&#xff1f; 最简单通俗的解释&#xff1a;HTTP 是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。 在Internet上的Web服务器上存放的都是超文本信息&#xff0c;客户机需要通过HTTP协议传输所要访问的超文本信息。 一、…

Adobe XD最新版号查询,如何使用?

Adobe XD是Adobe家推出的基于矢量的原型设计合作工具&#xff0c;被业界视为应对Sketch的“对抗”产品。Adobe XD不同于Sketch的系统限制&#xff0c;灵活性比较高&#xff0c;Windows和Mac都可以使用。自2017年推出以来&#xff0c;Adobe XD版经历了多次更新&#xff0c;这篇文…

【Python报错】已解决SyntaxError: can’t assign to function call

成功解决“SyntaxError: can’t assign to function call”错误的全面指南 在Python编程中&#xff0c;语法错误&#xff08;SyntaxError&#xff09;是初学者和经验丰富的开发者都可能遇到的问题。其中&#xff0c;“SyntaxError: can’t assign to function call”这个错误常…

IM即时通信技术

本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl IM&#xff0c;即Instant Messaging&#xff0c;是指即时通讯技术&#xff0c;它允许用户通过互联网实时交换文本、语音、视频、文件等多种形式的信息。这种技术打破了传统通信方式的时…

Spring AOP(实现,动态原理)详解版

Spring AOP 1.什么是AOP&#xff1f;1.1引入AOP依赖1.2编写AOP程序 2.Spring AOP核⼼概念2.1 切点(Pointcut)2.2连接点(Join Point)2.3通知(Advice)2.4 切⾯(Aspect) 3.通知类型3.1顺序3.2切⾯优先级 Order3.3 ⾃定义注解 MyAspect 4. Spring AOP 原理5 动态代理怎么实现5.1 JD…

大学数字媒体艺术设计网页设计试题及答案,分享几个实用搜题和学习工具 #媒体#职场发展

现在读书可不像小时候&#xff0c;以前想要校对试题答案&#xff0c;都得找到对应的纸质版答案查看&#xff0c;而且有的还只有答案&#xff0c;没有解析&#xff0c;无法弄清楚答案的由来。但是现在不一样了&#xff0c;现在我们可以通过搜题软件&#xff0c;寻找试题的答案&a…

性能优化随笔(一)

在软件开发过程中&#xff0c;一般要先实现功能方面的需求&#xff0c;功能方面的需求开发完毕之后&#xff0c;往往会考虑性能方面的优化。在业务发展的初期&#xff0c;性能往往能满足使用的需求&#xff0c;这时性能优化不是必不可少的。随着业务的发展&#xff0c;软件复杂…