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


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

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

Python-3.12.0文档解读

目录

​编辑​编辑​编辑我的写法:

代码点评

代码点评:

时间复杂度分析:

空间复杂度分析:

总结:

我要更强!

时间复杂度优化:

空间复杂度优化:

总结:

哲学和编程思想

举一反三

1. 效率优先 - 使用内置函数和库

2. 原地操作 - 利用列表推导式

3. 模块化与解耦 - 使用函数和类

4. 抽象与泛化 - 使用高阶函数

5. 简单性原则 - 避免过度设计

6. 优化与平衡 - 选择合适的数据结构

7. 可读性与可维护性 - 添加注释和文档


题目链接


我的写法:

# 读取输入的第一行,将第一个值赋给 N,第二个值赋给 C
N, C = map(int, input().split())

# 创建一个空列表 inputs,用于存储后续输入的数据
inputs = []

# 循环 N 次,每次读取一行输入,并将输入分割成列表,添加到 inputs 中
for i in range(N):
    inputs.append(input().split())

# 根据 C 的值选择不同的排序方式
if C == 1:
    # 如果 C 为 1,则按照列表中的第一个元素进行排序
    inputs = sorted(inputs, key=lambda x: x[0])
elif C == 2:
    # 如果 C 为 2,则先按照列表中的第二个元素进行排序,如果相同则再按照第一个元素排序
    inputs = sorted(inputs, key=lambda x: (x[1], x[0]))
elif C == 3:
    # 如果 C 为 3,则先按照列表中的第三个元素(将其转换为整数)进行排序,如果相同则再按照第一个元素排序
    inputs = sorted(inputs, key=lambda x: (int(x[2]), x[0]))

# 遍历排序后的 inputs 列表
for elem in inputs:
    # 将列表中的元素连接成一个字符串,元素之间用空格分隔,并打印出来
    print(' '.join(elem))

代码点评

这段代码的主要功能是读取输入数据,根据指定的列进行排序,并输出排序后的结果。下面是对这段代码的专业点评以及时间复杂度和空间复杂度的分析:

代码点评:

  1. 输入处理:代码通过 input().split() 读取输入,并将它们分割成列表。这种方式简单直观,适用于处理简单的输入格式。
  2. 排序逻辑:根据变量 C 的值,代码使用不同的排序键。这种设计允许用户通过改变 C 的值来指定排序的列,增加了代码的灵活性。
  3. 排序实现:使用 Python 的内置 sorted 函数,并结合 lambda 函数定义排序键。这是一种常见的做法,可以有效地对列表进行排序。
  4. 输出格式:使用 ' '.join(elem) 将列表转换为字符串并打印,保持了输入时的格式,使得输出清晰易读。

时间复杂度分析:

  1. 输入处理:读取和分割输入的时间复杂度为 O(N),其中 N 是输入的行数。
  2. 排序:sorted 函数的时间复杂度为 O(N log N),因为它是基于比较的排序算法。
  3. 输出:打印输出的时间复杂度为 O(N),因为需要遍历整个排序后的列表。

因此,总体的时间复杂度为 O(N + N log N + N) = O(N log N),主要受排序操作的影响。

空间复杂度分析:

  1. 输入存储:存储输入数据的空间复杂度为 O(N),因为需要存储每一行的数据。
  2. 排序:sorted 函数在原地排序时不需要额外的空间,但由于这里将排序结果赋值给了 inputs,所以空间复杂度也是 O(N)。
  3. 输出:输出操作不需要额外的空间。

因此,总体的空间复杂度为 O(N),主要由存储输入数据决定。

总结:

这段代码在功能上是完整的,能够根据用户指定的列对输入数据进行排序并输出。时间复杂度主要受排序操作的影响,为 O(N log N),而空间复杂度为 O(N)。在实际应用中,如果输入数据量较大,可能需要考虑优化排序算法或使用更高效的数据结构来减少时间和空间的开销。


我要更强!

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

  1. 减少不必要的排序:如果输入数据已经按照某个顺序排列,或者可以通过其他方式快速确定排序顺序,可以避免使用 sorted 函数。
  2. 原地排序:如果不需要保留原始列表,可以使用 list.sort() 方法进行原地排序,这样可以减少空间复杂度。
  3. 输入和输出的优化:如果输入和输出是瓶颈,可以考虑使用更高效的输入输出方法,如使用 sys.stdin.readline() 代替 input()。

下面是一个优化后的代码示例,使用了原地排序和更高效的输入输出方法:

import sys

# 读取输入的第一行,将第一个值赋给 N,第二个值赋给 C
N, C = map(int, sys.stdin.readline().split())

# 创建一个空列表 inputs,用于存储后续输入的数据
inputs = []

# 循环 N 次,每次读取一行输入,并将输入分割成列表,添加到 inputs 中
for i in range(N):
    inputs.append(sys.stdin.readline().split())

# 根据 C 的值选择不同的排序方式
if C == 1:
    # 如果 C 为 1,则按照列表中的第一个元素进行排序
    inputs.sort(key=lambda x: x[0])
elif C == 2:
    # 如果 C 为 2,则先按照列表中的第二个元素进行排序,如果相同则再按照第一个元素排序
    inputs.sort(key=lambda x: (x[1], x[0]))
elif C == 3:
    # 如果 C 为 3,则先按照列表中的第三个元素(将其转换为整数)进行排序,如果相同则再按照第一个元素排序
    inputs.sort(key=lambda x: (int(x[2]), x[0]))

# 遍历排序后的 inputs 列表
for elem in inputs:
    # 将列表中的元素连接成一个字符串,元素之间用空格分隔,并打印出来
    print(' '.join(elem))

时间复杂度优化:

  • 使用 sys.stdin.readline() 代替 input() 可以减少输入操作的时间复杂度。
  • 原地排序 list.sort() 的时间复杂度仍然是 O(N log N),但避免了创建新的列表,减少了空间复杂度。

空间复杂度优化:

  • 原地排序 list.sort() 不创建新的列表,因此空间复杂度保持在 O(N)。

总结:

这段代码在保持原有功能的基础上,通过原地排序和优化输入输出方法,减少了空间使用并可能提高输入输出的效率。时间复杂度仍然是 O(N log N),空间复杂度是 O(N)。在处理大量数据时,这些优化可以带来显著的性能提升。


哲学和编程思想

这段优化后的代码体现了以下哲学和编程思想:

  1. 效率优先:通过使用 sys.stdin.readline() 代替 input(),代码减少了输入操作的时间复杂度,体现了在编程中追求效率的思想。这种思想强调在处理大量数据时,应该尽可能减少不必要的计算和资源消耗。
  2. 原地操作:使用 list.sort() 进行原地排序,而不是创建一个新的排序后的列表,这体现了“不增加额外空间”的哲学。原地操作是一种常见的优化策略,它通过减少内存使用来提高程序的效率。
  3. 模块化与解耦:代码中的排序逻辑根据变量 C 的值进行不同的处理,这种设计使得排序功能模块化,易于理解和维护。同时,这种解耦也使得代码更加灵活,可以通过改变 C 的值来适应不同的排序需求。
  4. 抽象与泛化:使用 lambda 函数定义排序键,这是一种抽象和泛化的编程技巧。通过定义一个简单的函数作为排序键,可以灵活地指定排序的依据,而不需要为每种排序规则编写一个具体的函数。
  5. 简单性原则:代码保持了简单直观的风格,没有引入复杂的数据结构或算法。这种简单性原则(KISS原则,Keep It Simple, Stupid)是软件工程中的一个重要思想,它强调在设计中应该尽可能保持简单,以减少错误和提高可维护性。
  6. 优化与平衡:在优化时间和空间复杂度时,代码需要在两者之间找到一个平衡点。这里通过原地排序减少了空间使用,同时通过优化输入输出方法提高了时间效率。这种平衡考虑是编程中的一个重要思想,它要求开发者在不同的优化目标之间做出权衡。
  7. 可读性与可维护性:代码中的注释和清晰的结构有助于提高代码的可读性和可维护性。这是软件开发中的一个重要原则,它强调代码不仅是用来执行的,也是用来被其他开发者理解和修改的。

通过这些哲学和编程思想的应用,优化后的代码不仅提高了性能,也增强了代码的可读性和可维护性,符合现代软件开发的最佳实践。


举一反三

根据上述的哲学和编程思想,以下是一些具体的技巧和示例代码,帮助你举一反三:

1. 效率优先 - 使用内置函数和库

使用 Python 的内置函数和库通常比自己编写的代码更高效。例如,使用 map() 函数可以快速将列表中的元素转换为另一种类型。

# 使用 map 快速转换列表中的元素类型
numbers = ['1', '2', '3', '4', '5']
integers = list(map(int, numbers))

2. 原地操作 - 利用列表推导式

列表推导式是一种原地操作的技巧,它可以快速生成新的列表而不需要额外的空间。

# 使用列表推导式过滤列表中的偶数
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = [x for x in numbers if x % 2 == 0]

3. 模块化与解耦 - 使用函数和类

将代码分解为函数和类可以提高模块化和解耦。例如,创建一个函数来处理特定的排序逻辑。

def sort_by_criteria(data, criteria):
    if criteria == 1:
        return sorted(data, key=lambda x: x[0])
    elif criteria == 2:
        return sorted(data, key=lambda x: (x[1], x[0]))
    elif criteria == 3:
        return sorted(data, key=lambda x: (int(x[2]), x[0]))

# 使用函数进行排序
data = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
sorted_data = sort_by_criteria(data, 1)

4. 抽象与泛化 - 使用高阶函数

高阶函数如 map()、filter() 和 reduce() 可以接受函数作为参数,这使得代码更加抽象和泛化。

# 使用高阶函数 map 和 lambda 进行元素转换
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))

5. 简单性原则 - 避免过度设计

保持代码简单,避免引入不必要的复杂性。例如,如果一个简单的循环可以解决问题,就不要使用复杂的数据结构。

# 简单的循环解决问题
sum_of_numbers = 0
for num in numbers:
    sum_of_numbers += num

6. 优化与平衡 - 选择合适的数据结构

选择合适的数据结构可以平衡时间和空间复杂度。例如,使用集合(set)来快速查找元素。

# 使用集合快速查找元素
numbers = [1, 2, 3, 4, 5, 2, 3, 4]
unique_numbers = set(numbers)

7. 可读性与可维护性 - 添加注释和文档

为代码添加注释和文档可以提高其可读性和可维护性。

# 计算列表中所有元素的和
def sum_list(lst):
    """
    计算列表中所有元素的和。
    
    参数:
    lst (list): 包含数字的列表
    
    返回:
    int: 列表中所有元素的和
    """
    return sum(lst)

通过应用这些技巧,可以提高代码的效率、可读性和可维护性,同时保持代码的简洁和灵活。


感谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

用哲学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值