一个认为一切根源都是“自己不够强”的INTJ
个人主页:用哲学编程-CSDN博客
专栏:每日一题——举一反三
Python编程学习
Python内置函数
目录
迭代与增量开发(Iterative and Incremental Development):
算法和数据结构(Algorithms and Data Structures):
测试驱动开发(Test-Driven Development, TDD):
题目链接:https://pintia.cn/problem-sets/994805260223102976/exam/problems/type/7?problemSetProblemId=994805298269634560&page=0
我的写法(刚学Python时)
# 读取输入,将输入的字符串按空格分割成列表
times = input().split()
# 初始化索引变量i为0
i = 0
# 循环10次,将列表中的字符串转换为整数
while i < 10:
times[i] = eval(times[i]) # 将字符串转换为整数
i += 1
# 初始化一个空列表nums
nums = []
# 初始化索引变量i为0,j为1
i = 0
j = 1
# 循环10次,根据times列表中的数字生成nums列表
while i < 10:
while j <= times[i]:
nums.append(i) # 将当前的数字i添加到nums列表中
j += 1
i += 1
j = 1 # 重置j为1,为下一轮循环做准备
# 对nums列表进行排序
nums.sort()
# 初始化索引变量i为0
i = 0
# 查找nums列表中第一个大于0的元素,并将其移动到列表的开头
while i < len(nums):
if nums[i] > 0:
tmp = nums[i]
nums[1:i+1] = nums[:i] # 将i之前的元素向后移动一位
nums[0] = tmp # 将找到的第一个大于0的元素放到列表的第一个位置
break
i += 1
# 遍历nums列表,打印每个元素,不换行
for num in nums:
print(f"{num}", end='')
# 打印一个换行符,结束输出
print()
代码点评
这段代码实现了根据用户输入的10个数字(表示从0到9的每个数字在输出中出现的次数)来生成一个数字序列,并对序列进行排序和调整,确保第一个出现的非零数字位于序列的第一个位置。下面是对代码的点评:
- 输入处理:代码首先通过input().split()读取用户输入,并将输入的字符串按空格分割成列表。然后使用eval()函数将列表中的字符串转换为整数。这里使用eval()虽然方便,但存在安全风险,特别是当输入来自不可信源时。建议使用int()函数替代。
- 列表生成:代码通过两个嵌套循环生成nums列表,外层循环遍历0到9,内层循环根据times列表中的值重复添加数字。这种方法直观但效率不高,特别是当times中的值较大时。
- 排序和调整:代码对nums列表进行排序,然后查找并调整第一个非零元素到列表的开始位置。这部分逻辑清晰,但使用了切片操作来移动元素,这在Python中是比较耗时的操作。
- 输出:代码使用for循环遍历nums列表并打印每个元素,最后打印一个换行符。输出部分简洁明了。
时间复杂度分析
- 输入处理:O(10),因为只处理10个元素。
- 列表生成:O(n),其中n是所有数字出现的总次数。因为需要遍历每个数字并根据其出现次数生成元素。
- 排序:使用Python的内置sort()方法,时间复杂度为O(n log n)。
- 调整元素:O(n),因为需要遍历列表找到第一个非零元素,并移动元素。
- 输出:O(n),需要遍历整个列表。
总时间复杂度为O(n + n log n + n) = O(n log n),其中n是所有数字出现的总次数。
空间复杂度分析
- 存储输入:O(10),因为只存储10个元素。
- 生成列表:O(n),需要存储所有生成的数字。
总空间复杂度为O(n),其中n是所有数字出现的总次数。
总结
这段代码的逻辑清晰,但效率不是最优的,特别是对于大的输入数据。可以通过优化列表生成和元素移动的方式来提高效率。此外,输入处理部分应避免使用eval()函数,以提高代码的安全性。
我要更强
优化建议
- 输入处理:使用map()函数将字符串列表直接转换为整数列表,避免使用eval()。
- 列表生成:使用列表推导式简化代码,减少循环嵌套。
- 排序和调整:避免使用切片操作,改用交换元素的方式来调整列表。
- 输出:保持不变。
优化后的代码
# 读取输入,将输入的字符串按空格分割成列表,并转换为整数列表
times = list(map(int, input().split()))
# 使用列表推导式生成nums列表
nums = [i for i in range(10) for _ in range(times[i])]
# 对nums列表进行排序
nums.sort()
# 查找并调整第一个非零元素到列表的开始位置
for i in range(len(nums)):
if nums[i] > 0:
# 交换元素,将第一个非零元素移动到列表的第一个位置
nums[0], nums[i] = nums[i], nums[0]
break
# 遍历nums列表,打印每个元素,不换行
for num in nums:
print(f"{num}", end='')
# 打印一个换行符,结束输出
print()
时间复杂度和空间复杂度分析
- 输入处理:O(10),因为只处理10个元素。
- 列表生成:O(n),其中n是所有数字出现的总次数。使用列表推导式生成列表。
- 排序:O(n log n),使用Python的内置sort()方法。
- 调整元素:O(n),因为需要遍历列表找到第一个非零元素,并交换元素。
- 输出:O(n),需要遍历整个列表。
总时间复杂度为O(n + n log n + n) = O(n log n),其中n是所有数字出现的总次数。
- 存储输入:O(10),因为只存储10个元素。
- 生成列表:O(n),需要存储所有生成的数字。
总空间复杂度为O(n),其中n是所有数字出现的总次数。
总结
优化后的代码在逻辑上更加简洁,避免了不必要的循环和复杂的列表操作,提高了代码的效率和可读性。通过使用列表推导式和元素交换,减少了不必要的时间和空间开销。
哲学和编程思想
优化代码时所采用的方法体现了多种哲学和编程思想,具体包括:
-
简洁性(Simplicity):
- 使用列表推导式简化了代码结构,减少了嵌套循环的复杂性。这种简洁性不仅提高了代码的可读性,也使得代码更易于维护和理解。
-
抽象(Abstraction):
- 通过使用Python的内置函数如map()和sort(),代码抽象了底层的实现细节,使得开发者可以专注于问题的逻辑而不是具体的实现方法。
-
效率(Efficiency):
- 优化时间复杂度和空间复杂度的方法体现了对效率的追求。例如,避免使用eval()和切片操作,选择更高效的列表推导式和元素交换,都是为了减少不必要的计算和内存使用。
-
安全性(Security):
- 避免使用eval()函数,因为eval()可能执行任意代码,存在安全风险。这体现了在编程中对安全性的考虑,特别是在处理外部输入时。
-
迭代与增量开发(Iterative and Incremental Development):
- 通过逐步优化代码,每次关注一个小部分,如先优化输入处理,再优化列表生成,最后优化排序和输出,体现了迭代和增量开发的哲学。这种方法有助于逐步改进代码,同时易于测试和调试。
-
算法和数据结构(Algorithms and Data Structures):
- 理解并应用合适的数据结构(如列表)和算法(如排序)是编程中的核心思想。通过选择合适的数据结构和算法,可以显著提高程序的性能。
-
模块化(Modularity):
- 尽管代码本身较短,但通过将不同的功能(如输入处理、列表生成、排序等)分隔开来,体现了模块化的思想。这种模块化的结构有助于代码的组织和维护。
-
测试驱动开发(Test-Driven Development, TDD):
- 在优化过程中,可能需要编写测试用例来验证每个优化步骤是否正确。这种测试先行的方法有助于确保代码的正确性和稳定性。
通过这些哲学和编程思想的应用,优化后的代码不仅在性能上有所提升,而且在可读性、可维护性和安全性方面也有所增强。这些原则和思想是编程和软件开发中的重要组成部分,有助于构建高质量的软件系统。
举一反三
基于上述哲学和编程思想,以下是一些实用的技巧和建议,帮助你在编程时举一反三:
- 保持代码简洁:
- 使用Python的列表推导式、生成器表达式和函数式编程特性(如map()、filter()、reduce())来简化代码。
- 避免过度复杂的逻辑和嵌套,尽量保持代码的扁平化。
- 利用抽象:
- 使用现有的库和框架来避免重复造轮子。例如,使用NumPy或Pandas处理数据,使用Django或Flask构建Web应用。
- 创建和使用自己的函数和类来封装复杂的逻辑,提高代码的可重用性。
- 优化效率:
- 了解并应用时间复杂度和空间复杂度的概念,选择最合适的算法和数据结构。
- 使用性能分析工具(如Python的cProfile)来识别和优化瓶颈。
- 注重安全性:
- 在处理用户输入时,始终进行验证和清理,避免使用eval()等危险函数。
- 使用参数化查询或ORM(对象关系映射)来防止SQL注入攻击。
- 采用迭代和增量开发:
- 将大问题分解为小问题,逐步解决。每个小问题解决后,进行测试确保其正确性。
- 使用版本控制系统(如Git)来管理代码的迭代过程。
- 掌握算法和数据结构:
- 学习和练习常见的算法和数据结构,如排序算法、搜索算法、链表、树、图等。
- 在解决问题时,思考如何利用这些算法和数据结构来提高效率。
- 实践模块化:
- 将代码分解为模块或包,每个模块负责一个明确的功能。
- 使用接口和抽象类来定义模块之间的交互,提高代码的灵活性和可扩展性。
- 采用测试驱动开发:
- 在编写代码之前,先编写测试用例。这有助于明确需求,并确保代码的正确性。
- 使用单元测试框架(如Python的unittest或pytest)来编写和运行测试。
通过实践这些技巧,不仅能够提高编程效率和代码质量,还能够培养解决复杂问题的能力。记住,编程是一个不断学习和实践的过程,持续的练习和探索将帮助成为一个更优秀的程序员。