每日一题——Python实现PAT乙级1100 校庆(举一反三+思想解读+逐步优化)五千字好文


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

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

Python-3.12.0文档解读

目录

我的写法

代码结构和逻辑

时间复杂度分析

空间复杂度分析

总结

我要更强

方法一:直接处理输入,减少重复操作

优化点:

优化后的代码:

时间和空间复杂度分析:

方法二:预处理和一次遍历

优化点:

优化后的代码:

总结:

哲学和编程思想

举一反三


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

我的写法

# 读取输入的整数 N,表示朋友的数量
N = int(input())

# 创建一个空的集合来存储朋友的名字
friends = set()

# 初始化最老朋友的生日为一个较大的日期数值(20190101)
# 初始化最老朋友的名字为空字符串
oldest_friend_birthday = 20190101
oldest_friend = ""

# 循环读取每一个朋友的信息
for i in range(N):
    # 读取朋友的名字(假设包含生日信息)
    friend = input()
    
    # 将朋友添加到集合中
    friends.add(friend)
    
    # 提取朋友的生日信息,假设生日是名字的第6到第14个字符
    tmp = int(friend[6:14])
    
    # 检查当前朋友是否比已知的最老朋友更老
    if tmp < oldest_friend_birthday:
        # 更新最老朋友的生日和名字
        oldest_friend_birthday = tmp
        oldest_friend = friend

# 读取输入的整数 M,表示参与聚会的人数
M = int(input())

# 初始化最老的非朋友的生日为一个较大的日期数值(20190101)
# 初始化最老的非朋友的名字为空字符串
oldest_not_friend_birthday = 20190101
oldest_not_friend = ""

# 初始化出席的朋友的计数器
came_friends_num = 0

# 循环读取每一个出席者的信息
for i in range(M):
    # 读取出席者的名字
    came = input()
    
    # 提取出席者的生日信息,假设生日是名字的第6到第14个字符
    tmp = int(came[6:14])
    
    # 检查出席者是否在朋友集合中
    if came in friends:
        # 如果是朋友,计数器增加
        came_friends_num += 1
    else:
        # 如果不是朋友,检查他们是否比已知的最老非朋友更老
        if tmp < oldest_not_friend_birthday:
            # 更新最老非朋友的生日和名字
            oldest_not_friend = came
            oldest_not_friend_birthday = tmp

# 输出出席的朋友数量
print(came_friends_num)

# 如果有朋友出席,输出最老的朋友,否则输出最老的非朋友
if came_friends_num > 0:
    print(oldest_friend)
else:
    print(oldest_not_friend)

代码结构和逻辑

  1. 输入处理:
    • 代码首先读取校友的数量 N,然后读取每个校友的信息并存储在集合 friends 中。同时,它还会记录最老的校友信息。
    • 接着,代码读取参与校友会的人员数量 M,然后读取每个参与者的信息。对于每个参与者,代码会检查他们是否在 friends 集合中,并记录出席的校友数量。如果不是校友,代码会记录最老的非校友信息。
  2. 输出结果:
  • 最后,代码输出出席的校友数量,以及最老的校友或最老的非校友。

时间复杂度分析

  • 校友信息处理:
    • 读取和处理每个校友的信息需要 O(N) 时间,因为每个校友的信息都需要被读取和处理一次。
    • 查找最老的校友信息在最坏情况下需要遍历所有校友,因此也是 O(N) 时间。
  • 参与校友会人员信息处理:
  • 读取和处理每个参与者的信息需要 O(M) 时间,因为每个参与者的信息都需要被读取和处理一次。
  • 检查每个参与者是否在 friends 集合中需要 O(1) 时间(因为集合的查找操作是常数时间)。
  • 查找最老的非校友信息在最坏情况下需要遍历所有非校友,因此也是 O(M) 时间。

综合来看,整个代码的时间复杂度是 O(N + M)。

空间复杂度分析

  • 校友信息存储:
    • 存储所有校友的信息需要 O(N) 空间,因为每个校友的信息都被存储在集合 friends 中。
  • 参与校友会人员信息存储:
  • 存储最老的校友和最老的非校友信息需要常数空间,即 O(1) 空间。

综合来看,整个代码的空间复杂度是 O(N)。

总结

  • 时间复杂度:O(N + M)
  • 空间复杂度:O(N)

这段代码在时间和空间复杂度上都是高效的,特别是利用集合进行快速查找操作,使得整体性能得到了优化。


我要更强

在这个特定的场景下,优化时间复杂度和空间复杂度的余地并不是很大,因为我们需要处理和检查每个校友和参与者的信息。不过,我们可以考虑一些细微的改进来使代码更简洁和高效。

方法一:直接处理输入,减少重复操作

优化点:
  1. 直接在读取输入时做判断和记录,减少不必要的集合操作。
  2. 尽量合并条件判断逻辑,减少代码分支。

优化后的代码:

# 读取输入的整数 N,表示校友的数量
N = int(input())

# 初始化集合作为校友的集合
friends = set()

# 初始化最老校友的生日和名字
oldest_friend_birthday = 20190101
oldest_friend = ""

# 读取每个校友的信息并处理
for _ in range(N):
    friend = input()
    friends.add(friend)
    birthday = int(friend[6:14])
    if birthday < oldest_friend_birthday:
        oldest_friend_birthday = birthday
        oldest_friend = friend

# 读取输入的整数 M,表示参与校友会的人数
M = int(input())

# 初始化最老非校友的生日和名字
oldest_not_friend_birthday = 20190101
oldest_not_friend = ""

# 出席的校友数量
came_friends_num = 0

# 读取每个出席者的信息并处理
for _ in range(M):
    participant = input()
    birthday = int(participant[6:14])
    if participant in friends:
        came_friends_num += 1
    else:
        if birthday < oldest_not_friend_birthday:
            oldest_not_friend_birthday = birthday
            oldest_not_friend = participant

# 输出出席的校友数量
print(came_friends_num)

# 如果有校友出席,输出最老的校友,否则输出最老的非校友
if came_friends_num > 0:
    print(oldest_friend)
else:
    print(oldest_not_friend)

时间和空间复杂度分析:

  1. 时间复杂度:
    • 处理 N 个校友的信息:O(N)
    • 处理 M 个参与者的信息:O(M)
    • 综合时间复杂度:O(N + M)
  2. 空间复杂度:
  • 存储 N 个校友的信息:O(N)
  • 其他变量消耗的空间为常数级别:O(1)
  • 综合空间复杂度:O(N)

方法二:预处理和一次遍历

优化点:
  1. 在读取校友信息和参与者信息时,尽量减少不必要的变量和集合操作。
  2. 尽量使用单次遍历完成所有处理。

优化后的代码:

# 读取输入的整数 N,表示校友的数量
N = int(input())

# 初始化集合作为校友的集合
friends = set()

# 初始化最老校友的生日和名字
oldest_friend_birthday = 20190101
oldest_friend = ""

# 读取每个校友的信息并处理
for _ in range(N):
    friend = input()
    friends.add(friend)
    birthday = int(friend[6:14])
    if birthday < oldest_friend_birthday:
        oldest_friend_birthday = birthday
        oldest_friend = friend

# 读取输入的整数 M,表示参与校友会的人数
M = int(input())

# 初始化最老非校友的生日和名字
oldest_not_friend_birthday = 20190101
oldest_not_friend = ""

# 出席的校友数量
came_friends_num = 0

# 读取每个出席者的信息并处理
for _ in range(M):
    participant = input()
    birthday = int(participant[6:14])
    if participant in friends:
        came_friends_num += 1
    else:
        if birthday < oldest_not_friend_birthday:
            oldest_not_friend_birthday = birthday
            oldest_not_friend = participant

# 输出出席的校友数量
print(came_friends_num)

# 如果有校友出席,输出最老的校友,否则输出最老的非校友
if came_friends_num > 0:
    print(oldest_friend)
else:
    print(oldest_not_friend)

总结:

尽管在时间和空间复杂度上很难有进一步的优化空间,通过改进代码结构和逻辑,可以使代码更加简洁和高效。上述方法在保持原有复杂度的基础上,优化了代码的可读性和可维护性。


哲学和编程思想

在这些优化方法中,实际上运用了一些重要的编程原则和思想:

  1. DRY(Don't Repeat Yourself):就是避免重复的原则。我们尽量避免在代码中出现重复的或者相似的操作,比如我们在读取输入时就直接完成了一些检查和记录等操作,避免了之后再对这些数据进行额外的处理。
  2. 单一职责原则:这是面向对象编程中的一项基本原则,但也可以应用到函数式编程中。我们在处理每个参与者的信息时,只进行了与该参与者相关的操作(检查是否是校友、更新最老的非校友信息等),避免了将多个任务混在一起,使代码更清晰、更容易理解。
  3. 预先处理:在处理数据或解决问题之前,先进行一些预处理,可以让后续的操作更简单、更快。我们在读取校友信息时,就把他们存储在一个集合中,使得后续判断一个人是否是校友变得非常快速(集合的查找操作平均是 O(1) 时间复杂度)。
  4. 尽早返回:如果已经得到了最终结果,就应该尽早返回,避免进行不必要的操作。我们在找出出席的校友数量后,就可以根据这个数量决定输出最老的校友还是最老的非校友,而不需要再进行其他的检查或判断。
  5. KISS(Keep It Simple, Stupid):简单就是美。我们应该尽可能写出简单、直观、易于理解的代码。这也是我们在优化代码时的一个主要目标。
  6. YAGNI(You Ain't Gonna Need It):你不会需要它的原则。这是敏捷开发中的一项原则,指的是避免过早优化或添加不需要的功能。尽管我们讨论了一些优化方法,但其实在这个特定的场景下,原始的代码已经足够完成任务,无需过度优化。

Code Readability Counts:代码可读性很重要。一个好的代码应该是自解释的,尽可能减少注释的使用。在优化代码时,尽量让代码更简洁、更直观,以提高代码的可读性。


举一反三

  1. 数据结构选择:正确选择合适的数据结构可以极大地提升代码的性能。例如,在这个案例中,我们使用集合(set)来存储校友信息,因为集合的查找时间复杂度是O(1),这对于检查某人是否是校友而言是非常有效的。
  2. 预处理数据:当需要多次使用到某些数据或结果时,可以考虑预处理并存储这些数据或结果,以减少重复计算,提升代码运行效率。在这个案例中,我们预先读取并处理了所有的校友信息。
  3. 合并逻辑:当可能的时候,尝试合并处理逻辑,减少代码分支,这不仅可以提高代码的可读性,还能在一定程度上提高代码的效率。例如,我们在处理参与者信息时,将校友和非校友的处理逻辑合并,避免了额外的条件分支。
  4. 尽早筛选和返回:当代码中有多个可能的输出或结果时,可以通过尽早筛选并返回结果来提高代码的效率。例如,在我们的案例中,我们根据出席的校友数量尽早确定了输出的是最老的校友还是最老的非校友。
  5. 优化代码可读性:良好的代码可读性非常重要,它可以帮助你和其他开发者更容易地理解和维护代码。你可以通过合理的命名、保持函数/方法的单一职责、适当的注释等方式来提高代码的可读性。
  6. 避免过早优化:虽然优化是一个好的实践,但过早地进行优化可能会使代码变得复杂且难以理解。你应该首先确保代码的正确性,然后在必要的时候进行适当的优化。

以上就是基于这个案例和编程原则,可以学习并举一反三的一些技巧。


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

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

相关文章

中控室监控台在水处理行业的作用

随着工业化和城市化的快速推进&#xff0c;水处理行业的重要性日益凸显。作为确保水质安全、提高水资源利用效率的关键环节&#xff0c;水处理厂需要高效、稳定地运行。在这个过程中&#xff0c;中控室监控台发挥着不可或缺的作用。本文将从以下几个方面&#xff0c;详细阐述中…

Docker精华篇 - 常用命令大全,入门到精通!

大家好,我是CodeQi! 我们都知道 Docker 的重要性,以及 Docker 如何在软件开发生命周期中发挥重要作用 。 说实话,学习 Docker 很有趣,至少在我看来是这样。 一旦掌握了基础知识,这并不难。 困难的是记住所有这些命令。 因此,在这篇文章中,我收集了所有命令,或者更…

UG NX二次开发(C#)-根据草图创建拉伸特征(UFun+NXOpen)

文章目录 1、前言2、在UG NX中创建草图,然后创建拉伸特征3、基于UFun函数的实现4、基于NXOpen的实现代码1、前言 UG NX是基于特征的三维建模软件,其中拉伸特征是一个很重要的特征,有读者问如何根据草图创建拉伸特征,我在这篇博客中讲述一下草图创建拉伸特征的UG NX二次开发…

分享六款免费u盘数据恢复工具,U盘恢复工具集合【工具篇】

U盘里面的数据丢失了怎么找回&#xff1f;随着数字化时代的深入发展&#xff0c;U盘已成为我们日常生活中不可或缺的数据存储工具。然而&#xff0c;由于各种原因&#xff0c;如误删除、格式化、病毒攻击等&#xff0c;U盘中的数据可能会丢失&#xff0c;给用户带来极大的困扰。…

stm32中IIC通讯协议

参考资料&#xff1a;大部分均引用b站江协科技课程、GPT及网络资料 什么是IIC&#xff08;i2C&#xff09;通讯协议&#xff1f; 关键字&#xff1a;SCL、SDA、半双工、同步、串行。 IIC&#xff08;Inter-Integrated Circuit&#xff09;&#xff0c;也称为I2C&#xff08;In…

力扣双指针算法题目:双数之和,三数之和,四数之和

目录 一&#xff1a;双数之和 1.题目&#xff1a; 2.思路解析 3.代码 二&#xff1a;三数之和 1.题目 2.思路解析 3&#xff0c;代码 三&#xff1a;四数字之和 1.题目 2.思路解析 3.代码 一&#xff1a;双数之和 1.题目&#xff1a; 输入一个递增排序的数组和一…

思维导图插件--jsMind的使用

vue引入jsmind&#xff08;右键菜单&#xff09;_jsmind.menu.js-CSDN博客 第一版 vue-JsMind思维导图实现&#xff08;包含鼠标右键自定义菜单&#xff09;_jsmind 右键菜单-CSDN博客 // 新增节点addNode() {console.log(this.get_selected_nodeid());this.get_selected_…

uniapp入门

一、新建项目 进入到主界面&#xff0c;左上角点击新建——1.项目 输入项目名称&#xff0c;Vue版本选择3 二、创建页面 选中左侧文件目录里的pages文件夹&#xff0c;右键&#xff0c;选择新建页面 1输入名称 2选中“创建同名目录” 3选择模板&…

风暴统计案例复现 | 先单后多的影响因素分析

今日要复现的是最最基础的影响因素分析文章&#xff0c;文章包括了①基本情况表、②卡方检验、③多因素logistic回归&#xff0c;复现过程将会详细截图讲解具体步骤&#xff0c;尤其是新手小白&#xff0c;请大家跟上脚步哦&#xff01; 本文为常见的先单后多影响因素分析的文章…

类型“{}”上不存在属性“xxxx”。ts(2339)

解决&#xff1a;类型“{}”上不存在属性“xxxx”和非类型化函数调用不能接受类型参数等问题。 问题发现 今天一个学生&#xff0c;发我一张图&#xff08;如下&#xff09;。 他从远端拉取到本地&#xff08;自家电脑&#xff09;后打开的代码视图&#xff0c;一大堆抛红。问…

Golang | Leetcode Golang题解之第212题单词搜索II

题目&#xff1a; 题解&#xff1a; type Trie struct {children map[byte]*Trieword string }func (t *Trie) Insert(word string) {node : tfor i : range word {ch : word[i]if node.children[ch] nil {node.children[ch] &Trie{children: map[byte]*Trie{}}}nod…

【鸿蒙学习笔记】基础组件 Button

官方文档&#xff1a;按钮 (Button)添加链接描述 官方文档&#xff1a;button开发指导 目录标题 属性迭代完善不含子组件的按钮包含子组件的按钮ButtonType添加事件跳转超链接提交表单悬浮按钮 属性迭代完善 不含子组件的按钮 Column({ space: 10 }) {Row() {Button(添加子目…

CentOS 7 停止维护(2024-6-30)后可用在线yum源 —— 筑梦之路

众所周知&#xff0c;centos 7 在2024年6月30日&#xff0c;生命周期结束&#xff0c;官方不再进行支持维护&#xff0c;而很多环境一时之间无法完全更新替换操作系统&#xff0c;因此对于yum源还是需要的&#xff0c;特别是对于互联网环境来说&#xff0c;在线yum源使用方便很…

NoSQL之Redis优化

目录 一、Redis 高可用 二、Redis 持久化 1.RDB 持久化 1&#xff09;触发条件 2&#xff09; 执行流程 3&#xff09;启动时加载 2.AOF 持久化 1&#xff09;开启AOF 2&#xff09;执行流程 3&#xff09;启动时加载 3.RDB和AOF的优缺点 三、Redis 性能管理 1.查…

【Dison夏令营 Day 07】用 Python 和 Rich 制作 Wordle克隆(下篇)

在大流行期间&#xff0c;Wordle 在 Twitter 上还算比较流行的一款基于网络的益智游戏&#xff0c;要求玩家每天在六次或更短时间内猜出一个新的五个字母的单词&#xff0c;每个人得到的单词都是一样的。 在本教程中&#xff0c;你将在终端上创建自己的 Wordle 克隆。自 2021 …

分享一款Type C接口USB转2路485模块【带完整原理图】

大家好&#xff0c;我是『芯知识学堂』的SingleYork&#xff0c;今天给大家分享一款很实用的工具–基于Type C接口的USB转2路485模块。 这款模块主芯片采用南京沁恒的CH342F这款芯片&#xff0c;芯片特性如下&#xff1a; 该系列芯片有QFN24和ESSOP10 这2种封装&#xff0c;…

深度网络现代实践 - 深度前馈网络之结构设计篇

序言 深度网络结构设计作为人工智能领域的基石&#xff0c;正引领着技术创新的浪潮。通过模拟人脑神经元间的复杂连接&#xff0c;深度神经网络展现了卓越的特征学习与模式识别能力。随着大数据与计算能力的提升&#xff0c;设计高效、精准且泛化能力强的深度网络结构成为研究…

深度探索“目录名称无效“:原因、解决方案与最佳实践

目录名称无效&#xff1a;现象背后的秘密 在日常使用电脑或移动设备时&#xff0c;我们时常会遇到“目录名称无效”的错误提示&#xff0c;这一提示仿佛是一道无形的屏障&#xff0c;阻断了我们与重要数据的联系。从本质上讲&#xff0c;“目录名称无效”意味着系统无法识别或…

基于正点原子FreeRTOS学习笔记——时间片调度实验

目录 一、时间片调度介绍 二、实验演示 1、宏修改 1.1、滴答定时器宏 1.2、调度器宏 2、实验程序 2.1.1、任务1&#xff0c;任务2不加临界区程序 2.1.2 实验现象 2.2.1、任务1&#xff0c;任务2加临界区程序 2.2.2 实验现象 一、时间片调度介绍 时间片&#xff1a;同…

Golang中defer和return顺序

在Golang中&#xff0c;defer 和 return 的执行顺序是一个重要的特性&#xff0c;它们的执行顺序如下&#xff1a; return语句不是一条单独的语句&#xff0c;实际上&#xff0c;它是由赋值和返回两部分组成的。赋值步骤会先执行&#xff0c;这一步会计算return语句中的表达式…