每日一题——Python代码实现PAT甲级1006 Sign In and Sign Out(举一反三+思想解读+逐步优化)五千字好文


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

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

Python-3.12.0文档解读

目录

我的写法

代码点评

时间复杂度分析

空间复杂度分析

我要更强

优化建议

优化后的代码

时间复杂度和空间复杂度分析

优化说明

哲学和编程思想

抽象化(Abstraction):

模块化(Modularity):

效率优化(Efficiency Optimization):

数据驱动(Data-Driven):

迭代与增量开发(Iterative and Incremental Development):

算法和数据结构的选择(Algorithm and Data Structure Selection):

KISS原则(Keep It Simple, Stupid):

DRY原则(Don't Repeat Yourself):

单一职责原则(Single Responsibility Principle):

测试驱动开发(Test-Driven Development):

举一反三


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

我的写法

# 读取输入的M,表示接下来会有M行输入数据
M = int(input())

# 初始化变量,用于记录解锁和锁定的人以及对应的时间
who_unlocked = ''
who_locked = ''
time_unlocked = 235959  # 初始化为最大可能的时间(23:59:59)
time_locked = 0  # 初始化为最小可能的时间(00:00:00)

# 循环M次,每次处理一行输入数据
for i in range(M):
    # 读取一行输入,分割成三个部分:id_num(人员编号),in_time(进入时间),out_time(离开时间)
    id_num, in_time, out_time = input().split()
    
    # 将时间字符串转换为整数,去掉冒号,方便比较
    in_time = int(in_time.replace(':', ''))
    out_time = int(out_time.replace(':', ''))
    
    # 如果当前记录的进入时间早于已知的最早进入时间,则更新最早进入时间和对应的人员编号
    if in_time < time_unlocked:
        time_unlocked = in_time
        who_unlocked = id_num
    
    # 如果当前记录的离开时间晚于已知的最晚离开时间,则更新最晚离开时间和对应的人员编号
    if time_locked < out_time:
        time_locked = out_time
        who_locked = id_num

# 输出最早进入和最晚离开的人员编号
print(f"{who_unlocked} {who_locked}")

代码点评

这段代码实现了从用户输入中读取一系列人员的进出记录,并找出最早进入和最晚离开的人员编号。以下是对代码的专业点评:

  1. 输入处理:代码通过input()函数读取用户输入,并使用split()方法分割输入数据,这使得代码具有良好的交互性和灵活性。
  2. 时间处理:将时间字符串转换为整数,以便于比较。这种转换简化了时间比较的逻辑,但需要注意时间格式的统一性,确保所有时间都能正确转换。
  3. 逻辑清晰:代码通过两个变量time_unlocked和time_locked分别记录最早进入和最晚离开的时间,逻辑清晰,易于理解。
  4. 变量初始化:time_unlocked初始化为最大可能的时间,time_locked初始化为最小可能的时间,这是合理的初始化策略,确保在第一次比较时能够正确更新。
  5. 输出格式:使用格式化字符串f"{who_unlocked} {who_locked}"输出结果,简洁明了。

时间复杂度分析

  • 读取输入:每次读取一行输入,时间复杂度为O(M),其中M是输入的行数。
  • 字符串处理:每次处理一行输入中的时间字符串,时间复杂度为O(1),因为每次操作都是固定的。
  • 循环:外层循环执行M次,每次循环内部的时间复杂度为O(1),因此总的时间复杂度为O(M)。

综上,这段代码的时间复杂度为O(M)。

空间复杂度分析

  • 存储输入:每次循环中,存储三个变量(id_num, in_time, out_time),空间复杂度为O(1)。
  • 存储结果:存储两个时间变量和两个人员编号变量,空间复杂度为O(1)。

由于空间复杂度不随输入规模M的增加而增加,因此这段代码的空间复杂度为O(1)。

总结,这段代码在时间和空间效率上都表现良好,逻辑清晰,适合处理此类问题。


我要更强

优化建议

  1. 输入优化:可以一次性读取所有输入,然后进行处理,这样可以减少每次读取输入的开销。
  2. 时间处理优化:可以使用更高效的数据结构(如字典)来存储人员和时间的关系,这样可以快速查找和更新。
  3. 逻辑优化:可以合并判断条件,减少不必要的比较。

优化后的代码

# 一次性读取所有输入,并分割成列表
all_inputs = [input().split() for _ in range(int(input()))]

# 初始化字典,用于存储每个人员的最早进入时间和最晚离开时间
person_times = {}

# 处理输入数据
for id_num, in_time_str, out_time_str in all_inputs:
    # 将时间字符串转换为整数
    in_time = int(in_time_str.replace(':', ''))
    out_time = int(out_time_str.replace(':', ''))
    
    # 如果人员编号不在字典中,初始化其时间记录
    if id_num not in person_times:
        person_times[id_num] = {'in_time': in_time, 'out_time': out_time}
    else:
        # 更新最早进入时间和最晚离开时间
        person_times[id_num]['in_time'] = min(person_times[id_num]['in_time'], in_time)
        person_times[id_num]['out_time'] = max(person_times[id_num]['out_time'], out_time)

# 找出最早进入和最晚离开的人员编号
earliest_in = min(person_times, key=lambda x: person_times[x]['in_time'])
latest_out = max(person_times, key=lambda x: person_times[x]['out_time'])

# 输出结果
print(f"{earliest_in} {latest_out}")

时间复杂度和空间复杂度分析

  • 时间复杂度:读取所有输入的时间复杂度为O(M),处理输入的时间复杂度为O(M),查找最早进入和最晚离开的时间复杂度为O(M)。因此,总的时间复杂度为O(M)。
  • 空间复杂度:存储所有人员的时间记录,空间复杂度为O(M),其中M是输入的行数。

优化说明

  1. 输入优化:通过列表推导一次性读取所有输入,减少了多次调用input()的开销。
  2. 时间处理优化:使用字典存储每个人员的最早进入时间和最晚离开时间,可以快速查找和更新。
  3. 逻辑优化:通过字典的键值对存储,简化了更新逻辑,减少了不必要的比较。

这种优化方法在处理大量数据时更为高效,特别是在输入数据量较大时,能够显著提升性能。


哲学和编程思想

优化代码的过程中融入了多种哲学和编程思想,以下是一些主要的思想:

  1. 抽象化(Abstraction):

    • 通过使用字典来存储人员和时间的关系,抽象化了数据的存储和访问方式,使得代码更加简洁和易于理解。
  2. 模块化(Modularity):

    • 代码中的每个功能(如输入处理、时间转换、结果输出)都被模块化为独立的步骤,这有助于代码的维护和测试。
  3. 效率优化(Efficiency Optimization):

    • 通过一次性读取所有输入和使用字典来存储数据,减少了重复的输入操作和提高了数据访问的速度,体现了对程序运行效率的追求。
  4. 数据驱动(Data-Driven):

    • 代码的逻辑主要围绕数据处理展开,通过分析和操作数据来解决问题,这是数据驱动编程的体现。
  5. 迭代与增量开发(Iterative and Incremental Development):

    • 优化过程可以看作是一个迭代和增量的过程,每次优化都基于前一次的结果,逐步改进代码的性能和可读性。
  6. 算法和数据结构的选择(Algorithm and Data Structure Selection):

    • 选择合适的数据结构(如字典)来存储和操作数据,这是算法设计中的关键步骤,直接影响程序的效率。
  7. KISS原则(Keep It Simple, Stupid):

    • 代码优化过程中尽量保持简单,避免过度复杂化,这有助于提高代码的可读性和可维护性。
  8. DRY原则(Don't Repeat Yourself):

    • 通过抽象和模块化,避免了代码的重复,这是DRY原则的体现,有助于减少错误和提高代码质量。
  9. 单一职责原则(Single Responsibility Principle):

    • 每个函数或模块只负责一个功能,这有助于保持代码的清晰和易于维护。
  10. 测试驱动开发(Test-Driven Development):

  • 虽然代码中没有直接体现,但在实际开发中,优化后的代码应该通过测试来验证其正确性和性能,这是测试驱动开发的思想。

这些哲学和编程思想在优化代码的过程中相互交织,共同指导着代码的改进和优化。通过应用这些思想,可以提高代码的质量、效率和可维护性。


举一反三

掌握这些哲学和编程思想后,可以将它们应用到更广泛的编程场景中,以下是一些技巧和建议,帮助举一反三:

  1. 抽象化与模块化:
    • 在设计程序时,尝试将复杂的问题分解为更小的、可管理的部分。每个部分应该负责一个明确的功能,并且可以独立测试和维护。
    • 使用类和对象来封装数据和操作,这样可以提高代码的可重用性和可维护性。
  2. 效率优化:
    • 分析代码中的瓶颈,通常是循环和数据处理部分。优化这些部分可以显著提高整体性能。
    • 使用合适的数据结构和算法来解决问题。例如,如果需要频繁查找,使用哈希表(如Python中的字典)通常比列表更高效。
  3. 数据驱动:
    • 当面对需要处理大量数据的问题时,考虑数据的特点和结构,设计适合的数据模型和处理流程。
    • 使用数据库或数据存储服务来管理数据,这样可以更有效地处理和查询数据。
  4. 迭代与增量开发:
    • 采用敏捷开发方法,将项目分解为多个小迭代,每个迭代都包含设计、编码、测试和反馈。
    • 在每个迭代中,专注于实现最重要的功能,然后逐步添加更多功能。
  5. 算法和数据结构的选择:
    • 学习和理解不同的算法和数据结构,了解它们的时间和空间复杂度,以及适用场景。
    • 在解决问题时,首先考虑是否存在已知的算法或数据结构可以应用。
  6. KISS原则:
    • 编写代码时,尽量保持简单明了,避免过度设计。
    • 使用清晰的命名和注释,确保代码易于理解和维护。
  7. DRY原则:
    • 避免在代码中重复相同的逻辑。如果发现重复,考虑将其抽象为一个函数或模块。
    • 使用配置文件或环境变量来管理重复的设置,而不是在代码中硬编码。
  8. 单一职责原则:
    • 确保每个函数、类或模块只做一件事,并且做好这件事。
    • 当一个组件变得过于复杂时,考虑将其分解为更小的组件。
  9. 测试驱动开发:
  • 在编写代码之前,先编写测试用例。这有助于确保代码的正确性,并且可以作为文档来指导代码的实现。
  • 定期运行测试,确保代码的稳定性和可靠性。

通过将这些哲学和编程思想应用到实际的编程实践中,可以提高代码的质量,减少错误,并且更有效地解决问题。记住,编程不仅仅是写代码,更是一种思维方式和解决问题的艺术。

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

用哲学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值