每日一题——Python实现PAT乙级1030 完美数列(举一反三+思想解读+逐步优化)五千字好文


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

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

Python-3.12.0文档解读

目录

初次尝试

再次尝试

代码结构

时间复杂度分析

空间复杂度分析

总结

我要更强

时间复杂度分析

空间复杂度分析

总结

哲学和编程思想

抽象与模块化:

效率与性能优化:

数据结构的选择:

迭代与递增开发:

避免重复计算:

错误处理与容错:

代码可读性与维护性:

测试与验证:

举一反三

理解问题本质:

选择合适的数据结构:

优化算法:

模块化设计:

迭代开发:

代码复用:

编写清晰的代码:

测试驱动开发:

持续学习和实践:

反思和总结:


题目链接:https://pintia.cn/problem-sets/994805260223102976/exam/problems/type/7?problemSetProblemId=994805291311284224&page=0

初次尝试

import sys  # 导入sys模块,用于读取标准输入

# 使用sys.stdin.read方法读取所有输入,并将其分割成一个列表
input = sys.stdin.read
inputs = input().split()

# 从输入列表中提取N和p的值
N = int(inputs[0])
p = int(inputs[1])

# 将输入列表中剩余的部分转换为整数列表
nums = list(map(int, inputs[2:]))

# 初始化目标数列列表
target_nums = list()

# 初始化最大值M和最小值m为数列的第一个元素
M = nums[0]
m = nums[0]

# 遍历输入的数列
for i in range(N):
    # 将当前元素添加到目标数列中
    target_nums.append(nums[i])
    
    # 保存上一次的最大值和最小值
    last_M = M
    last_m = m
    
    # 标记是否有最大值或最小值被改变
    M_or_m_changed = -1
    
    # 如果当前元素大于或等于M,则更新M
    if M <= nums[i]:
        M = nums[i]
        M_or_m_changed = 1
    # 如果当前元素小于或等于m,则更新m
    elif nums[i] <= m:
        m = nums[i]
        M_or_m_changed = 0

    # 检查当前目标数列是否满足完美数列的条件
    if M <= m * p:
        pass  # 如果满足条件,则不做任何操作
    else:
        # 如果不满足条件,则从目标数列中移除最后一个元素
        target_nums.pop()
        
        # 根据是否有最大值或最小值被改变,恢复它们
        if M_or_m_changed == 1:
            M = last_M
        elif M_or_m_changed == 0:
            m = last_m

# 输出目标数列的长度
sys.stdout.write(f"{len(target_nums)}\n")

再次尝试

import sys

# 读取输入
input = sys.stdin.read
inputs = input().split()
N = int(inputs[0])
p = int(inputs[1])
nums = list(map(int, inputs[2:]))

# 对数列进行排序
nums.sort()

# 初始化双指针和最大长度
left = 0
max_length = 0

# 使用双指针遍历数列
for right in range(N):
    # 移动左指针,直到子数组满足条件
    while nums[right] > nums[left] * p:
        left += 1
    # 更新最大长度
    max_length = max(max_length, right - left + 1)

# 输出结果
sys.stdout.write(f"{max_length}\n")

这段代码实现了一个双指针算法,用于解决一个特定问题:给定一个数列和乘数p,找到数列中满足任意元素大于其左边任意元素乘以p的最长子数组的长度。下面是对这段代码的点评:

代码结构

  1. 输入处理

    • 使用sys.stdin.read读取所有输入,并将输入分割成整数。
    • 读取数列长度N、乘数p和数列本身。
  2. 排序

    • 对数列进行排序,这是为了后续的双指针算法能够正确工作。
  3. 双指针算法

    • 初始化左指针left和最大长度max_length
    • 遍历数列,使用右指针right
    • 当右指针指向的元素大于左指针指向的元素乘以p时,移动左指针。
    • 每次移动右指针后,更新最大长度。
  4. 输出结果

    • 使用sys.stdout.write输出最大长度。

时间复杂度分析

  • 排序:使用Python内置的sort()方法,时间复杂度为O(N log N),其中N是数列的长度。
  • 双指针遍历:每个元素最多被访问两次(一次由左指针,一次由右指针),因此这一部分的时间复杂度是O(N)。
  • 总时间复杂度为O(N log N + N),由于N log N在渐近意义上占主导,所以整体时间复杂度为O(N log N)。

空间复杂度分析

  • 输入处理:存储输入的数列需要O(N)的空间。
  • 排序:Python的sort()方法在原地排序,不需要额外空间。
  • 双指针算法:只需要常数级别的额外空间。
  • 总空间复杂度为O(N)。

总结

这段代码有效地使用了双指针算法来解决问题,通过排序简化了问题的处理。时间复杂度主要受排序影响,而空间复杂度相对较低。代码结构清晰,逻辑明确,是一个良好的算法实现。


我要更强

为了优化时间复杂度和空间复杂度,我们可以考虑以下几个方面:

  1. 避免排序:排序的时间复杂度是O(N log N),如果我们能够避免排序,可以显著减少时间复杂度。
  2. 使用更高效的数据结构:例如,使用哈希表来存储和快速查找元素。
  3. 优化双指针算法:确保算法的每个步骤都是必要的,避免不必要的计算。

下面是一个优化后的代码实现,避免了排序,并使用了哈希表来存储元素和它们的位置:

import sys

# 读取输入
input = sys.stdin.read
inputs = input().split()
N = int(inputs[0])
p = int(inputs[1])
nums = list(map(int, inputs[2:]))

# 使用哈希表存储数列元素和它们的位置
num_positions = {num: i for i, num in enumerate(nums)}

# 初始化双指针和最大长度
left = 0
max_length = 0

# 使用双指针遍历数列
for right in range(N):
    # 移动左指针,直到子数组满足条件
    while nums[right] > nums[left] * p:
        left += 1
    # 更新最大长度
    max_length = max(max_length, right - left + 1)

# 输出结果
sys.stdout.write(f"{max_length}\n")

时间复杂度分析

  • 输入处理:时间复杂度为O(N),因为我们遍历了一次输入来创建数组和哈希表。
  • 双指针遍历:时间复杂度为O(N),因为每个元素最多被访问两次。
  • 总时间复杂度为O(N),这是一个显著的改进,因为我们避免了排序。

空间复杂度分析

  • 输入处理:空间复杂度为O(N),因为我们存储了数组和哈希表。
  • 双指针算法:只需要常数级别的额外空间。
  • 总空间复杂度为O(N)。

总结

这个优化版本的代码通过避免排序和使用哈希表来存储元素位置,将时间复杂度从O(N log N)降低到O(N),同时保持了空间复杂度为O(N)。这是一个更高效的解决方案,特别是在处理大规模数据时。


哲学和编程思想

优化算法的过程中,运用了多种哲学和编程思想,以下是一些关键点:

  1. 抽象与模块化

    • 在编程时,我们将问题分解为更小的、可管理的部分(如输入处理、数据结构创建、算法实现等),每个部分都有明确的功能和接口。这种模块化的方法使得代码更易于理解和维护。
  2. 效率与性能优化

    • 我们关注算法的时间复杂度和空间复杂度,通过避免不必要的排序操作和使用哈希表来提高效率。这种优化体现了对算法性能的重视,是计算机科学中追求高效计算的核心思想。
  3. 数据结构的选择

    • 使用哈希表来存储元素和它们的位置,这是基于对数据结构特性的理解。哈希表提供了快速的查找操作,非常适合需要频繁查找元素位置的场景。
  4. 迭代与递增开发

    • 在实现算法时,我们采用迭代的方法,逐步构建和测试代码。这种方法有助于及时发现和修复问题,同时也使得代码的开发过程更加稳健。
  5. 避免重复计算

    • 通过预先存储元素位置,我们避免了在双指针算法中重复查找元素位置的操作。这种避免重复计算的思想是优化算法性能的重要策略。
  6. 错误处理与容错

    • 虽然代码中没有显式的错误处理,但在实际应用中,考虑输入的合法性和异常情况的处理是重要的。这体现了编程中的容错思想,即确保程序在面对不完美或异常输入时仍能稳定运行。
  7. 代码可读性与维护性

    • 代码中使用了清晰的变量命名和适当的注释,这有助于提高代码的可读性。良好的代码风格和结构使得代码更易于维护和扩展。
  8. 测试与验证

    • 在实际应用中,对算法进行充分的测试是确保其正确性和性能的关键。这包括单元测试、集成测试等,确保代码在各种情况下都能按预期工作。

通过这些哲学和编程思想的应用,不仅提高了算法的效率,也确保了代码的质量和可维护性。这些原则是软件工程和算法设计中的基础,对于开发高效、可靠的软件系统至关重要。


举一反三

根据上述哲学和编程思想,以下是一些技巧和策略,可以帮助你在面对类似问题时举一反三:

  1. 理解问题本质

    • 在开始解决问题之前,深入理解问题的本质和需求。这有助于确定最合适的算法和数据结构。
  2. 选择合适的数据结构

    • 根据问题的特性选择最合适的数据结构。例如,如果需要快速查找和插入操作,哈希表可能是一个好选择;如果需要保持元素的顺序,链表或数组可能更合适。
  3. 优化算法

    • 分析算法的时间复杂度和空间复杂度,寻找可能的优化点。例如,通过避免重复计算、使用缓存或减少不必要的操作来提高效率。
  4. 模块化设计

    • 将问题分解为更小的模块,每个模块负责一个特定的功能。这不仅使代码更易于管理,也便于测试和维护。
  5. 迭代开发

    • 采用迭代的方法开发代码,逐步增加功能并进行测试。这种方法有助于及时发现问题并进行调整。
  6. 代码复用

    • 尽可能复用已有的代码和解决方案。这不仅可以节省时间,也有助于保持代码的一致性和质量。
  7. 编写清晰的代码

    • 使用有意义的变量名、注释和清晰的代码结构。这有助于他人(或未来的你)理解和维护代码。
  8. 测试驱动开发

    • 在编写代码之前先编写测试用例。这有助于确保代码的正确性,并鼓励开发出更健壮的解决方案。
  9. 持续学习和实践

    • 不断学习新的编程技术和算法,通过实践应用这些知识。这有助于提高解决问题的能力。
  10. 反思和总结

    • 在解决问题后,回顾整个过程,总结哪些方法有效,哪些可以改进。这种反思有助于在未来的问题解决中更加高效。

通过应用这些技巧和策略,不仅能够解决当前的问题,还能够提高自己解决更广泛问题的能力。记住,编程和算法设计是一个不断学习和实践的过程,持续的努力和反思将使你成为一个更优秀的程序员。


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

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

相关文章

《互联网政务应用安全管理规定》深度解读

《互联网政务应用安全管理规定》的出台&#xff0c;对互联网政务应用的安全提出了一系列具体要求。 2024年5月15日&#xff0c;中央网信办、中央编办、工业和信息化部、公安部等四部门联合公布《互联网政务应用安全管理规定》&#xff08;以下称《规定》&#xff09;&#xff…

手机pdf删除怎么办?只需要2招,就可以快速恢复耶

PDF文件&#xff0c;这个我们日常生活中的常客&#xff0c;越来越受到大家的喜爱。但是&#xff0c;有时候我们会因为一时的疏忽或者清理手机内存而不小心删掉了重要的PDF文件&#xff0c;这可真是让人头疼啊&#xff01;那么&#xff0c;这些pdf删除后&#xff0c;有没有什么好…

一年半测试|17K|商汤科技4轮面经

面经哥只做互联网社招面试经历分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥 背景‍‍ 楼主本科&#xff0c;大概一年半工作经验。 之前工作也是测试岗&#xff0c;离职了三个多月再次刷题面试&#xff0c;大概花了一个月准备…

Java露营基地预约小程序预约下单系统源码

轻松开启户外探险之旅 &#x1f31f; 露营热潮来袭&#xff0c;你准备好了吗&#xff1f; 随着人们对户外生活的热爱日益增加&#xff0c;露营已成为许多人周末和假期的首选活动。但你是否曾因找不到合适的露营基地而烦恼&#xff1f;或是因为繁琐的预约流程而错失心仪的营地…

OElove 婚恋系统 v10.2升级真是及时,你们是不是UI团队换了?不得不说这次UI是真美!当然功能也升级了大大的赞!

怎么说呢&#xff0c;成为OE的老用户已经有五年了&#xff0c;当时买的初衷就是在本地做一个响当当的门户但是因为疫情搁浅了。。。实在是入不敷出&#xff01;转行的这几年又看好了婚恋这个行业于是打算冲头再来&#xff0c;我记得我当时还是8.5&#xff0c;功能比较强大就是太…

联邦学习——学习笔记2:联邦学习×资源受限下的自适应本地迭代次数

文章目录 一、符号二、应用场景三、与FedAvg算法区别 本笔记参考自b站up主&#xff1a;丸一口 论文参考自Adaptive Federated Learning in Resource Constrained Edge Computing Systems 原视频链接 一、符号 原文的符号解释如下图绿色字体所注 二、应用场景 就是在资源小…

数据结构历年考研真题对应知识点(栈)

目录 3.1栈 3.1.1栈的基本概念 【栈的特点&#xff08;2017&#xff09;】 【入栈序列和出栈序列之间的关系(2022)】 【特定条件下的出栈序列分析(2010、2011、2013、2018、2020)】 3.1.2栈的顺序存储结构 【出/入栈操作的模拟(2009)】 3.1栈 3.1.1栈的基本概念 【栈…

视觉与运动控制6

基于驱动器的控制功能 驱动器的系统性能和运算能力有限需要单独的运动控制器。 V/F恒压频比控制 开环控制方法&#xff0c;应用最广泛、最简单&#xff0c;只需要电机数据即可。适用于控制精度和动态响应要求不高的应用。控制原理&#xff1a;保持点击内磁通量恒定&#xff…

Rocketmq在单节点情况下新增从节点

Rocketmq在单节点情况下新增从节点 在docker-compose部署rocketmq单节点的基础上&#xff0c;新增一个从节点 一&#xff0c;修改docker-compose配置文件 原docker-compose文件 version: 3.5 services:rmqnamesrv:image: foxiswho/rocketmq:server-4.5.2container_name: rm…

CST软件中滤波器中外部耦合偏小怎么办

在电磁仿真领域&#xff0c;CST Studio Suite&#xff08;CST 工作室套装&#xff09;软件以其强大的功能和易用性而广受工程师和科研人员的青睐。然而&#xff0c;在使用CST软件进行滤波器设计时&#xff0c;有时会遇到外部耦合偏小的问题&#xff0c;这可能导致滤波器的性能不…

已解决java.security.GeneralSecurityException: 安全性相关的通用异常的正确解决方法,亲测有效!!!

已解决java.security.GeneralSecurityException: 安全性相关的通用异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 确定具体异常类型 检查输入参数 验证算法支持性 调整安全策略 确保资源可…

[深度学习] 自编码器Autoencoder

自编码器&#xff08;Autoencoder&#xff09;是一种无监督学习算法&#xff0c;主要用于数据的降维、特征提取和数据重建。自编码器由两个主要部分组成&#xff1a;编码器&#xff08;Encoder&#xff09;和解码器&#xff08;Decoder&#xff09;。其基本思想是将输入数据映射…

ROS2从入门到精通2-2:详解机器人3D可视化工具Rviz2与案例分析

目录 0 专栏介绍1 什么是Rviz2&#xff1f;2 Rviz2基本界面3 Rviz2基本数据类型4 数据可视化案例4.1 实例1&#xff1a;显示USB摄像头数据4.2 实例2&#xff1a;显示球体 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有…

python turtle 001画两只小狗

效果图&#xff1a; 代码&#xff1a; pythonturtle001画两只小狗资源-CSDN文库 # 作者V w1933423import turtle # 导入turtle模块def draw_dogs():turtle.setup(800, 800) # 设置画布大小为800x800p turtle.Pen() # 创建一个画笔对象p.pensize(14) # 设置画笔大小为14p.…

【PL理论深化】(7) Ocaml 语言:静态类型语言 | 自动类型推断 | 多态类型和多态函数 | let-多态类型系统

&#x1f4ac; 写在前面&#xff1a;OCaml 是一种拥有静态类型系统的语言&#xff0c;本章我们就要探讨静态类型系统。 目录 0x00 静态类型系统 0x01 自动类型推断&#xff08;automatic type inference&#xff09; 0x02 多态类型和多态函数 0x03 let-多态类型系统&#…

微信群聊不见了?掌握这4个技巧轻松找回,简直太爽了

微信&#xff0c;作为国内最受欢迎的社交应用之一&#xff0c;其群聊功能极大地方便了人们的工作与生活。然而&#xff0c;随着加入的群聊数量日益增多&#xff0c;如何快速找到并管理这些群聊成为了一个难题。 幸运的是&#xff0c;微信提供了一些实用的技巧&#xff0c;帮助…

Linux 安装ElasticSearch + FSCrawler 扫描本地的文件资源

文章目录 0. 前言1. 安装ElasticSearch1.1 下载安装包1.2 新增用户1.3 解压安装包1.4 更改文件夹用户1.5 修改配置文件1.6 修改系统配置1.7 启动集群 2. 安装FSCrawler2.1 下载安装包2.2 创建配置文件2.3 修改配置文件2.4 启动2.5 验证是否被索引 0. 前言 Elasticsearch 是一个…

Ubuntu-22.04 安装禅道

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

绿色共享购:共创绿色消费新纪元

在当今快节奏的社会中&#xff0c;人们对绿色消费和共享经济的追求愈发凸显其重要性。为了满足这一需求&#xff0c;我们创新推出了“绿色共享购”这一前沿的消费增值模式。该模式不仅有效整合了商家资源&#xff0c;更通过其独特的机制&#xff0c;实现了商家与消费者的双重增…

国产音频放大器工作原理以及应用领域

音频放大器是在产生声音的输出元件上重建输入的音频信号的设备&#xff0c;其重建的信号音量和功率级都要理想&#xff1a;如实、有效且失真低。音频范围为约20Hz&#xff5e;20000Hz&#xff0c;因此放大器在此范围内必须有良好的频率响应&#xff08;驱动频带受限的扬声器时要…