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


一个认为一切根源都是“自己不够强”的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.mfbz.cn/a/693168.html

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

相关文章

无头+单向+非循环链表的实现

这里写目录标题 1. 链表1.1 链表的概念及结构1.2 链表的分类 2. 接口实现3. 链表的实现3.1 打印链表3.2 头插3.3 尾插3.4 头删3.5 尾删3.6 单链表查找3.7 在pos之前插入3.8 在pos之后插入3.9 删除pos位置的值3.10 删除pos位置之后的值3.11 链表的释放3.12 动态申请一个节点 4. …

STM32F103C8T6 HAL库串口重定向

前言&#xff1a; 这里仅用做个人记录&#xff0c;实现USART1串口通信&#xff0c;并通过printf重定向输出“串口打印测试” 正文开始&#xff1a; 首先在STM32CubeMX上对串口进行配置&#xff0c;其实方法也非常简单。 按照箭头顺序&#xff0c;先点击Connectivity找到USART1…

30分钟吃掉pytorch转onnx及推理

pytorch模型线上部署最常见的方式是转换成onnx然后再转成tensorRT 在cuda上进行部署推理。 本文介绍将pytorch模型转换成onnx模型并进行推理的方法。 #!pip install onnx #!pip install onnxruntime #!pip install torchvision 公众号算法美食屋后台回复关键词&#xff1a;源码…

jmeter -n -t 使用非GUI模式运行脚本说明

命令模式下执行jmx文件 jmeter -n -t fatie.jmx -l results\t4.jtl -e -o results\h1 表示以命令行模式运行当前目录下的脚本fatie.jmx,将结果存入当前目录下的results\t1.jtl,并且生成html格式的报告&#xff0c;写入文件夹results\h1。 说明&#xff1a;生成结果的文件夹r…

《精通ChatGPT:从入门到大师的Prompt指南》第10章:案例分析

第10章&#xff1a;案例分析 10.1 优秀Prompt案例解析 在深入探讨如何精通ChatGPT的使用之前&#xff0c;理解并分析一些优秀的Prompt案例是至关重要的。这不仅有助于更好地掌握Prompt的构建技巧&#xff0c;还能提高与AI交互的效果。在这一节中&#xff0c;我们将详细解析一…

实用的 C 盘搬家软件

一、简介 1、一款专门用于 Windows 系统的文件夹移动工具&#xff0c;它允许用户将程序或游戏的安装文件夹从一台驱动器移动到另一台驱动器&#xff0c;或者同一个驱动器内的不同路径&#xff0c;而无需重新安装或破坏现有的程序安装。 二、下载 1、下载地址&#xff1a; 官网链…

1-Maven-settings配置

1-Maven-settings配置 整理下Maven工具的使用。 【本地仓库、私服、镜像仓库、远程仓库、中央仓库】 本文基于阅读其他博客和对公司Maven配置的学习整理出来的。希望通过本此学习能对Maven有个整体性的掌控。 顺序&#xff1a;profile.repository > pom文件中的repository &…

关于焊点检测(SJ-BIST)模块实现

关于焊点检测&#xff08;SJ-BIST&#xff09;模块实现 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a;ISE、Vivado、Quartus II 关于焊点检测&#xff08;SJ-BIST&#xff09;模块实现一、引言二、焊点检测功能的实现方法&#xff08;1&#xff09; 输入接口&#x…

SpringBoot+Vue网上超市(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 用户管理员 功能截图

C基础与SDK调试方法

REVIEW 上次学习了一下软件使用流程zynq PS点灯-CSDN博客 本次学习一下C编程基础与调试方法 1. 硬件编程原理 小梅哥视频链接&#xff1a; 07_Xilinx嵌入式裸机硬件编程原理_哔哩哔哩_bilibili 对应的课程笔记&#xff1a;【zynq课程笔记】【裸机】【第7课 】【硬件编程原理…

eNSP学习——配置RIP路由附加度量值

目录 主要命令 原理概述 实验目的 实验内容 实验拓扑 实验编址 实验步骤 1、基本配置 2、搭建RIP网络 3、配置RIP Metricin 4、配置RIP Metricout 需要eNSP各种配置命令的点击链接自取&#xff1a;华为&#xff45;NSP各种设备配置命令大全PDF版_ensp配置命令大全资…

Vyper重入漏洞解析

什么是重入攻击 Reentrancy攻击是以太坊智能合约中最具破坏性的攻击之一。当一个函数对另一个不可信合约进行外部调用时&#xff0c;就会发生重入攻击。然后&#xff0c;不可信合约会递归调用原始函数&#xff0c;试图耗尽资金。 当合约在发送资金之前未能更新其状态时&#…

计算机网络-数制转换与子网划分

目录 一、了解数制 1、计算机的数制 2、二进制 3、八进制 4、十进制 5、十六进制 二、数制转换 1、二进制转十进制 2、八进制转十进制 3、十六进制转十进制 4、十进制转二进制 5、十进制转八进制 6、十进制转十六进制 三、子网划分 1、IP地址定义 2、IP的两种协…

Linux之进程信号详解【上】

&#x1f30e; Linux信号详解 文章目录&#xff1a; Linux信号详解 信号入门 技术应用角度的信号 信号及信号的产生       信号的概念       信号的处理方式 信号的产生方式         键盘产生信号         系统调用产生信号         软件…

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:隧道和矿井绘图设备

RockMass 正在努力打入采矿业和隧道工程利基市场。 这家位于多伦多的初创公司正在利用 NVIDIA AI 开发一款绘图平台&#xff0c;帮助工程师评估矿井和施工中的隧道稳定性。 目前&#xff0c;作为安全预防措施&#xff0c;地质学家和工程师会站在离岩石五米远的地方&#xff0…

Llama模型家族之Stanford NLP ReFT源代码探索 (二)Intervention Layers层

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

【Java 百“练”成钢】Java 基础:类和对象

Java 基础&#xff1a;类和对象 01.打印信息02.打印类的简单名称03.打印类的 ClassLoader04.获取类的方法05.获取类的Package06.创建一个对象数组07.计算圆的面积08.计算圆的周长09.创建具有私有访问修饰符的成员10.创建带访问修饰符的成员11.将对象作为参数传递12.通过类对象获…

开源多平台AI音乐生成器本地安装结合cpolar内网穿透实现远程访问

文章目录 前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固定公网地址 前言 本文主要介绍如何在Windows系统电脑上快速本地部署一个文字生成音乐的AI创作工具MusicGPT&#xff0c;并结合cpolar内网穿透工具实现随时随地远程访问使用。 MusicG…

Linux 35.5 + JetPack v5.1.3@ ego-planner编译安装

Linux 35.5 JetPack v5.1.3 ego-planner编译安装 1. 源由2. 编译&安装Step 1&#xff1a;依赖库安装Step 2&#xff1a;建立工程Step 3&#xff1a;编译工程Step 4&#xff1a;安装工程 3. 问题汇总3.1 planner/plan_env - OpenCV3.2 uav_simulator/local_sensing - CUDA优…

基于非下采样小波包分析的滚动轴承故障诊断(MATLAB R2021B)

小波变换具有良好的时频局部化特性和多分辨率特性&#xff0c;可准确定位信号的突变点并可在不同尺度上描述信号的局部细节特征&#xff0c;被广泛应用于信号降噪。但标准正交小波变换不具有平移不变性&#xff0c;采用标准正交小波对信号消噪后&#xff0c;会在脉冲尖峰处产生…