每日一题遇到沙比题目——Python实现PAT甲级1061 Dating(举一反三+思想解读+逐步优化)


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

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

Python-3.12.0文档解读

目录

吐槽题目

我的写法

代码分析

1. 输入处理

2. 变量初始化

3. 查找星期几和小时

4. 查找分钟

5. 输出结果

时间复杂度

空间复杂度

总结

我要更强

优化后的代码

优化分析

时间复杂度

空间复杂度

哲学和编程思想

1. KISS(Keep It Simple, Stupid)

2. DRY(Don't Repeat Yourself)

3. 提前退出(Early Exit)

4. 最小化状态(Minimize State)

5. 空间换时间(Space-Time Tradeoff)

6. 高内聚低耦合(High Cohesion and Low Coupling)

7. 单一职责原则(Single Responsibility Principle, SRP)

8. 最小惊讶原则(Principle of Least Astonishment)

举一反三

1. 简化设计

2. 消除重复

3. 提前退出

4. 最小化状态

5. 空间换时间

6. 高内聚低耦合

7. 单一职责原则

8. 最小惊讶原则



 题目链接


吐槽题目


这道题描述有问题,小时数应该是找到第一个共有的大写字母之后的那个共有字符而不是题目所描述的第二个共有字符。让我浪费1小时,无语!!!!!

我的写法

import sys

# 读取标准输入
input = sys.stdin.read

# 去除输入数据的前后空白,并按空白字符分割成列表
data = input().strip().split()

# 将输入的四个字符串分别赋值给 first_str、second_str、third_str 和 fourth_str
first_str = data[0]
second_str = data[1]
third_str = data[2]
fourth_str = data[3]

# 初始化存储星期几、小时和分钟的变量
weekday = ""
hour = ""
minute = ""

# 定义一个列表,包含星期一到星期日的缩写
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]

# 布尔变量,用于指示是否已找到第一个匹配的大写字母
found_first = False

# 遍历 first_str 和 second_str 中每个字符的位置(长度取两者的最小值)
for i in range(min(len(first_str), len(second_str))):
    # 如果两个字符串在某位置的字符相同
    if first_str[i] == second_str[i]:
        # 如果还未找到第一个大写字母且该字符在 'A' 到 'G' 之间
        if not found_first and 'A' <= first_str[i] <= 'G':
            # 将 weekday 设为相应的星期几(通过 days 列表和字符的 ASCII 码计算得出)
            weekday = days[ord(first_str[i]) - ord('A')]
            # 更新 found_first 为 True
            found_first = True
        # 如果已找到第一个大写字母
        elif found_first:
            # 如果该字符是数字 '0' 到 '9' 之间,将其转换为整数并赋值给 hour
            if '0' <= first_str[i] <= '9':
                hour = int(first_str[i])
                break
            # 如果该字符是 'A' 到 'N' 之间,将其转换为对应的小时值并赋值给 hour(通过字符的 ASCII 码计算得出)
            elif 'A' <= first_str[i] <= 'N':
                hour = 10 + ord(first_str[i]) - ord('A')
                break

# 遍历 third_str 和 fourth_str 中每个字符的位置(长度取两者的最小值)
for i in range(min(len(third_str), len(fourth_str))):
    # 如果两个字符串在某位置的字符相同且该字符是字母
    if third_str[i] == fourth_str[i] and third_str[i].isalpha():
        # 将该位置的索引赋值给 minute
        minute = i
        break

# 打印结果,格式为 星期几 小时:分钟,小时和分钟都以两位数显示(不足两位的前面补零)
print(f"{weekday} {hour:02d}:{minute:02d}")

这段代码的主要功能是从四个输入字符串中解析出一个特定的时间信息,其中包括星期几、小时和分钟。代码的实现步骤包括:

  1. 读取输入数据并进行预处理。
  2. 初始化存储星期几、小时和分钟的变量。
  3. 通过遍历前两个字符串来确定星期几和小时。
  4. 通过遍历后两个字符串来确定分钟。
  5. 最终输出格式化的结果。

代码分析

1. 输入处理

python复制

input = sys.stdin.read

data = input().strip().split()

first_str = data[0]

second_str = data[1]

third_str = data[2]

fourth_str = data[3]

  • 从标准输入中读取数据,并按空白字符分割成列表形式。
  • 将列表中的四个元素分别赋值给 first_str、second_str、third_str 和 fourth_str。
2. 变量初始化

python复制

weekday =

""

hour = ""

minute = ""

days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]

found_first = False

  • 初始化存储星期几、小时和分钟的变量。
  • 使用一个布尔变量 found_first 来指示是否已找到第一个匹配的大写字母。
  • days 列表包含星期一到星期日的缩写,对应字符 'A' 到 'G'。
3. 查找星期几和小时

python复制

for i in range(min(len(first_str), len(second_str))):

if first_str[i] == second_str[i]:

if not found_first and 'A' <= first_str[i] <= 'G':

weekday = days[ord(first_str[i]) - ord('A')]

found_first = True

elif found_first:

if '0' <= first_str[i] <= '9':

hour = int(first_str[i])

break

elif 'A' <= first_str[i] <= 'N':

hour = 10 + ord(first_str[i]) - ord('A')

break

  • 通过遍历 first_str 和 second_str,找到第一个匹配的字符并判断其是否在 'A' 到 'G' 之间以确定星期几。
  • 如果已找到第一个匹配字符,再寻找下一个匹配字符以确定小时。
4. 查找分钟

python复制

for i in range(min(len(third_str), len(fourth_str))):

if third_str[i] == fourth_str[i] and third_str[i].isalpha():

minute = i

break

  • 通过遍历 third_str 和 fourth_str,找到第一个匹配的字母以确定分钟。
5. 输出结果

python复制

print(f"{weekday} {hour:02d}:{minute:02d}")

  • 按指定格式输出结果,确保小时和分钟都以两位数显示。

时间复杂度

  • 遍历 first_str 和 second_str 的长度取决于较短的字符串长度,时间复杂度为 O(n)。
  • 遍历 third_str 和 fourth_str 的长度也是取决于较短的字符串长度,时间复杂度为 O(m)。
  • 总体时间复杂度为 O(n + m),其中 n 和 m 分别是两组字符串的最小长度。

空间复杂度

  • 变量 weekday、hour 和 minute 以及 found_first 和 days 列表占用常数空间。
  • 额外使用的空间主要是输入数据存储,假设输入数据长度为 k,则空间复杂度为 O(k)。
  • 总体空间复杂度为 O(k)。

总结

这段代码在时间复杂度和空间复杂度上都表现良好,能够高效地处理输入数据并解析出所需的时间信息。代码结构清晰,逻辑合理,适用于输入规模较大的场景。


我要更强

在这段代码中,时间复杂度和空间复杂度已经相对较优。但是,我们可以通过减少冗余操作和更精简的逻辑来进一步优化。以下是一些优化的思路:

  1. 合并变量初始化和输入读取:减少不必要的分步骤操作。
  2. 合并遍历逻辑:将查找星期几和小时的遍历合并,减少循环次数。
  3. 减少空间占用:尽可能使用局部变量和避免重复存储来减少空间复杂度。
  4. 提前终止循环:一旦找到所需的字符,即可提前退出循环,避免多余的遍历。

优化后的代码

import sys

# 读取标准输入并处理
input = sys.stdin.read().strip().split()
first_str, second_str, third_str, fourth_str = input

# 定义星期几的列表
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]

# 初始化变量
weekday = ""
hour = ""
minute = ""

# 用于标记是否找到了第一个大写字母
found_first = False

# 遍历 first_str 和 second_str,长度取两者的最小值
for i in range(min(len(first_str), len(second_str))):
    if first_str[i] == second_str[i]:
        if not found_first:
            if 'A' <= first_str[i] <= 'G':
                weekday = days[ord(first_str[i]) - ord('A')]
                found_first = True
        else:
            if '0' <= first_str[i] <= '9':
                hour = int(first_str[i])
                break
            elif 'A' <= first_str[i] <= 'N':
                hour = 10 + ord(first_str[i]) - ord('A')
                break

# 遍历 third_str 和 fourth_str,长度取两者的最小值
for i in range(min(len(third_str), len(fourth_str))):
    if third_str[i] == fourth_str[i] and third_str[i].isalpha():
        minute = i
        break

# 打印格式化结果
print(f"{weekday} {hour:02d}:{minute:02d}")

优化分析

时间复杂度
  • 对于查找星期几和小时的循环,时间复杂度仍然是 O(n),其中 n 是 first_str 和 second_str 的最小长度。
  • 对于查找分钟的循环,时间复杂度仍然是 O(m),其中 m 是 third_str 和 fourth_str 的最小长度。
  • 综合时间复杂度依旧是 O(n + m),但通过合并逻辑和提前终止循环,提升了实际运行效率。
空间复杂度
  • 输入数据的存储空间复杂度为 O(k),其中 k 是输入字符串的总长度。
  • 其他变量如 weekday、hour、minute 等占用常数空间。
  • 总体空间复杂度为 O(k),并没有增加额外的存储需求。

通过这些优化,减少了冗余操作,使得代码更加简洁高效。在处理大规模输入数据时,优化后的代码将更加高效。


哲学和编程思想

在这段代码的优化过程中,应用了一些重要的哲学和编程思想。以下是具体说明:

1. KISS(Keep It Simple, Stupid)

这是一种设计原则,强调简单性。简单的设计更容易理解、维护和调试。

  • 应用:通过减少不必要的分步骤操作(如合并变量初始化和输入读取),使代码更加简洁和直接。

2. DRY(Don't Repeat Yourself)

这是一个编程原则,旨在减少代码重复,提高代码的可维护性。

  • 应用:通过合并遍历逻辑,将查找星期几和小时的循环合并,避免了重复的遍历操作。

3. 提前退出(Early Exit)

这一原则建议在满足某些条件后立即退出循环或函数,以避免不必要的计算。

  • 应用:在找到所需的字符后立即退出循环,减少无效的遍历操作。

4. 最小化状态(Minimize State)

这一原则建议在程序中尽量减少需要维护的状态变量,以简化程序逻辑。

  • 应用:通过减少全局变量的使用,尽量使用局部变量,这样可以降低程序的复杂性和出错概率。

5. 空间换时间(Space-Time Tradeoff)

这一思想在算法设计中非常重要,它指出我们可以通过使用更多的空间来减少时间复杂度,反之亦然。

  • 应用:在这个优化过程中,我们通过使用局部变量减少了空间复杂度,但在时间复杂度上没有做出牺牲,因为空间换时间在这里并不适用。

6. 高内聚低耦合(High Cohesion and Low Coupling)

这一原则强调模块内部应高度相关,而模块之间的依赖应尽量减少。

  • 应用:通过将功能逻辑集中在一起(如将输入处理、变量初始化和遍历逻辑合并),提高了代码的内聚性,减少了模块间的依赖。

7. 单一职责原则(Single Responsibility Principle, SRP)

每个模块或函数应该只有一个职责或功能,这样更容易理解和维护。

  • 应用:每个循环只负责一个具体的任务(一个负责查找星期几和小时,另一个负责查找分钟),使得代码更具可读性和可维护性。

8. 最小惊讶原则(Principle of Least Astonishment)

代码应当以一种最不让人感到惊讶的方式工作,使用常见的约定和直观的方式来实现功能。

  • 应用:通过使用直观的变量名和清晰的逻辑,使得代码更容易理解,不会让读者感到困惑。

通过这些优化和编程思想的应用,代码不仅在性能上得到了提升,而且在可读性、可维护性和可靠性上也得到了增强。


举一反三

当然,可以通过理解这些编程原则,将它们灵活应用于不同的场景,来提升编程技能。以下是一些技巧,帮助你更好地举一反三:

1. 简化设计

技巧: 在设计代码时,先从最简单的方案入手,然后逐步添加复杂性。

  • 实践: 在写函数时,先写出主要逻辑,然后再考虑异常处理和边界条件。

2. 消除重复

技巧: 在编码过程中,时刻警惕重复的代码片段,考虑是否能将其抽象为函数或模块。

  • 实践: 定期审查代码,寻找重复的逻辑,并尝试将其重构为通用函数。

3. 提前退出

技巧: 在循环或判断中,一旦满足条件,就立即退出,避免不必要的计算。

  • 实践: 在编写循环和条件判断时,优先考虑提前退出策略(如return、break、continue等)。

4. 最小化状态

技巧: 尽量避免使用全局变量,优先使用局部变量,保持代码的独立性。

  • 实践: 在函数内部定义变量,确保这些变量只在函数内部使用。

5. 空间换时间

技巧: 当需要优化性能时,分析是否可以通过增加空间消耗来减少时间复杂度。

  • 实践: 在处理大数据集时,考虑使用哈希表(字典)来快速查找,提高查询速度。

6. 高内聚低耦合

技巧: 设计模块时,确保模块内部的功能高度相关,同时减少模块之间的依赖关系。

  • 实践: 使用面向对象的编程(OOP)思想,将相关功能封装到类中,并通过接口减少耦合。

7. 单一职责原则

技巧: 确保每个函数或模块只负责一项功能,避免职责过多导致代码复杂化。

  • 实践: 在编写函数时,明确函数的单一职责,并将不同功能拆分为多个小函数。

8. 最小惊讶原则

技巧: 使用常见的编程约定和清晰的命名,确保代码易于理解和维护。

  • 实践: 遵循团队的代码风格指南,使用通俗易懂的变量名和函数名。

通过这些技巧,可以在多种编程场景中灵活应用上述原则,使代码更简洁、高效、易于维护。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

用哲学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值