提示词
我最近正在准备python组算法竞赛,由于我之前是 c++选手 , 对于python的一些算法竞赛常用的语法和工具不是很熟悉,你现在充当我的竞赛导师,指导我学习python用于算法竞赛的知识。
包括但不仅限于以下问题的作答:
1.最基本的数字,字符串,字符等的输入输出,还有字符串,数字的一些操作等等,特别例如多个数字,字符的读取(输入之间有空格)等等。
2.常用数据结构的操控(每一种的增删改查,排序,反转等等),此外对于py数组,你需要重点讲解每一个部分。尤其是算法竞赛常用的 , 比如优先队列 ,等等
3.py一些语法特性例如语法糖等等,有很多不要仅提供语法糖的介绍。
4.自带的算法库,例如排序等等,注意,不要仅提供排序的介绍 , 需要有多重排序方式 , 比如升降序 , 自定义排序 ;
注意:
1.注意须要保证全面且易懂,且非常详细,复杂的地方标注注释。不用担心篇幅不够,有多少写多少。
2.对于每一个知识点,给出不下于15个的案例,每个案例都包含不同的知识,就是不重复,并且配有详细的注释和说明。
3.针对算法竞赛,python一些独有的技巧你要给出介绍,另外Python比较由于其他语言的功能或语法工具等的优势你要提一下(例如整形不会溢出)。
5.上述我所要求的内容只是给你一个说明,只是告诉你你应该写哪些内容,但远远不仅仅只是这些,你需要考虑和扩展更多。
6.蓝桥杯官方要求的是只能使用Python3.8版本,且只能使用Python自带的库与语法等等,也就是你从官网安装的原生的Python,你给的示例里不应该包含其他库,例如需要pip或者conda安装的库。
关于你的作答:
1.你的制造者限制了你一次回答的最大输出字符量,我不知道你是否知道这件事情,他们应该没有告诉你,这样的话在一次性的对话里你肯定无法将所有的内容展现出来。但是现在你知道了,所以不用担心字数,尽可能多的写,如果你的输出出现中断我会说继续,这样你就接着写。
2.如果你的输出出现了中断,且正好在代码块里出现中断,那么接下来回答的时候注意在开头加上```
3.请注意格式,标题,序号等等。
Python 算法竞赛指南
一、基本输入输出与字符串、数字操作
1.1 基本输入输出
Python 中的 input()
函数用于获取用户输入,print()
函数用于输出。对于算法竞赛来说,掌握如何快速读取和处理数据是非常重要的。
- 单个值的输入输出
# 输入一个整数并输出
n = int(input())
print(n)
# 输入一个浮点数并输出
f = float(input())
print(f)
# 输入一个字符串并输出
s = input()
print(s)
- 多个值的输入(以空格分隔)
# 输入一行包含多个整数,并将它们转换为列表
nums = list(map(int, input().split()))
print(nums)
# 输入一行包含多个浮点数,并将它们转换为列表
floats = list(map(float, input().split()))
print(floats)
# 输入一行包含多个字符串,并将它们转换为列表
words = input().split()
print(words)
- 多行输入
# 输入 n 行,每行一个整数
n = int(input())
numbers = [int(input()) for _ in range(n)]
print(numbers)
# 输入 n 行,每行多个整数
n = int(input())
matrix = [list(map(int, input().split())) for _ in range(n)]
print(matrix)
1.2 字符串操作
字符串是算法竞赛中常见的数据类型之一,了解其常用操作可以提高解题效率。
- 字符串拼接
# 使用 + 拼接字符串
s1 = "Hello"
s2 = "World"
result = s1 + " " + s2
print(result) # 输出: Hello World
# 使用 join() 方法拼接字符串列表
words = ["Hello", "World"]
result = " ".join(words)
print(result) # 输出: Hello World
- 字符串切片
# 获取字符串的子串
s = "HelloWorld"
print(s[0:5]) # 输出: Hello
print(s[5:]) # 输出: World
print(s[:5]) # 输出: Hello
print(s[-5:]) # 输出: World
print(s[::-1]) # 输出: dlroWolleH (反转字符串)
- 字符串查找
# 查找子串的位置
s = "HelloWorld"
print(s.find("World")) # 输出: 5
print(s.index("World")) # 输出: 5 (如果找不到会抛出异常)
# 统计子串出现次数
print(s.count("l")) # 输出: 3
- 字符串替换
# 替换子串
s = "HelloWorld"
new_s = s.replace("World", "Python")
print(new_s) # 输出: HelloPython
- 字符串大小写转换
# 转换为大写
s = "hello"
print(s.upper()) # 输出: HELLO
# 转换为小写
s = "HELLO"
print(s.lower()) # 输出: hello
# 首字母大写
s = "hello world"
print(s.capitalize()) # 输出: Hello world
# 每个单词首字母大写
print(s.title()) # 输出: Hello World
- 去除空白字符
# 去除两端空白字符
s = " hello "
print(s.strip()) # 输出: hello
# 去除左端空白字符
print(s.lstrip()) # 输出: hello
# 去除右端空白字符
print(s.rstrip()) # 输出: hello
- 字符串分割
# 按空格分割字符串
s = "Hello World"
print(s.split()) # 输出: ['Hello', 'World']
# 按指定字符分割字符串
s = "apple,banana,orange"
print(s.split(',')) # 输出: ['apple', 'banana', 'orange']
- 字符串格式化
# 使用 % 进行格式化
name = "Alice"
age = 25
print("My name is %s and I am %d years old." % (name, age))
# 使用 format() 方法
print("My name is {} and I am {} years old.".format(name, age))
# 使用 f-string (Python 3.6+)
print(f"My name is {name} and I am {age} years old.")
1.3 数字操作
在算法竞赛中,对数字的操作也非常重要,包括但不限于加减乘除、取模等。
- 基本运算
# 加法
a = 5
b = 3
print(a + b) # 输出: 8
# 减法
print(a - b) # 输出: 2
# 乘法
print(a * b) # 输出: 15
# 除法
print(a / b) # 输出: 1.6666666666666667
# 整除
print(a // b) # 输出: 1
# 取余
print(a % b) # 输出: 2
# 幂运算
print(a ** b) # 输出: 125
- 数学函数
import math
# 绝对值
print(abs(-5)) # 输出: 5
# 最大值
print(max(1, 2, 3)) # 输出: 3
# 最小值
print(min(1, 2, 3)) # 输出: 1
# 四舍五入
print(round(3.7)) # 输出: 4
# 向上取整
print(math.ceil(3.2)) # 输出: 4
# 向下取整
print(math.floor(3.7)) # 输出: 3
# 开方
print(math.sqrt(16)) # 输出: 4.0
# 对数
print(math.log(10)) # 输出: 2.302585092994046
# 三角函数
print(math.sin(math.pi / 2)) # 输出: 1.0
- 随机数生成
import random
# 生成一个随机整数
print(random.randint(1, 10)) # 输出: [1, 10] 之间的随机整数
# 生成一个随机浮点数
print(random.random()) # 输出: [0, 1) 之间的随机浮点数
# 从列表中随机选择一个元素
lst = [1, 2, 3, 4, 5]
print(random.choice(lst)) # 输出: 列表中的一个随机元素
# 打乱列表顺序
random.shuffle(lst)
print(lst) # 输出: 打乱后的列表
二、常用数据结构的操控
2.1 列表(List)
列表是 Python 中最常用的数据结构之一,支持增删改查、排序、反转等操作。
- 创建列表
# 创建空列表
lst = []
# 创建包含元素的列表
lst = [1, 2, 3, 4, 5]
# 使用 range() 创建列表
lst = list(range(1, 6))
print(lst) # 输出: [1, 2, 3, 4, 5]
- 访问元素
# 访问单个元素
lst = [1, 2, 3, 4, 5]
print(lst[0]) # 输出: 1
print(lst[-1]) # 输出: 5
# 访问子列表
print(lst[1:4]) # 输出: [2, 3, 4]
- 添加元素
# 在末尾添加元素
lst = [1, 2, 3]
lst.append(4)
print(lst) # 输出: [1, 2, 3, 4]
# 在指定位置插入元素
lst.insert(1, 0)
print(lst) # 输出: [1, 0, 2, 3, 4]
# 合并两个列表
lst.extend([5, 6])
print(lst) # 输出: [1, 0, 2, 3, 4, 5, 6]
- 删除元素
# 删除指定位置的元素
lst = [1, 2, 3, 4, 5]
del lst[2]
print(lst) # 输出: [1, 2, 4, 5]
# 删除指定值的元素
lst.remove(4)
print(lst) # 输出: [1, 2, 5]
# 弹出最后一个元素
last = lst.pop()
print(last) # 输出: 5
print(lst) # 输出: [1, 2]
# 清空列表
lst.clear()
print(lst) # 输出: []
- 修改元素
# 修改指定位置的元素
lst = [1, 2, 3, 4, 5]
lst[2] = 0
print(lst) # 输出: [1, 2, 0, 4, 5]
- 查找元素
# 查找元素索引
lst = [1, 2, 3, 4, 5]
print(lst.index(3)) # 输出: 2
# 统计元素出现次数
print(lst.count(2)) # 输出: 1
- 排序
# 升序排序
lst = [3, 1, 4, 1, 5, 9]
lst.sort()
print(lst) # 输出: [1, 1, 3, 4, 5, 9]
# 降序排序
lst.sort(reverse=True)
print(lst) # 输出: [9, 5, 4, 3, 1, 1]
# 自定义排序规则
lst = [("apple", 2), ("banana", 1), ("orange", 3)]
lst.sort(key=lambda x: x[1])
print(lst) # 输出: [('banana', 1), ('apple', 2), ('orange', 3)]
# 多重排序
lst = [("apple", 2, 10), ("banana", 1, 5), ("orange", 3, 8)]
lst.sort(key=lambda x: (x[1], x[2]))
print(lst) # 输出: [('banana', 1, 5), ('apple', 2, 10), ('orange', 3, 8)]
- 反转
# 反转列表
lst = [1, 2, 3, 4, 5]
lst.reverse()
print(lst) # 输出: [5, 4, 3, 2, 1]
2.2 元组(Tuple)
元组与列表类似,但它是不可变的,即一旦创建就不能修改。
- 创建元组
# 创建空元组
tup = ()
# 创建包含元素的元组
tup = (1, 2, 3, 4, 5)
# 单个元素的元组需要加逗号
tup = (1,)
- 访问元素
# 访问单个元素
tup = (1, 2, 3, 4, 5)
print(tup[0]) # 输出: 1
print(tup[-1]) # 输出: 5
# 访问子元组
print(tup[1:4]) # 输出: (2, 3, 4)
- 元组解包
# 解包元组
tup = (1, 2, 3)
a, b, c = tup
print(a, b, c) # 输出: 1 2 3
# 忽略部分元素
a, *rest = (1, 2, 3, 4, 5)
print(a, rest) # 输出: 1 [2, 3, 4, 5]
- 元组转换为列表
# 将元组转换为列表
tup = (1, 2, 3, 4, 5)
lst = list(tup)
print(lst) # 输出: [1, 2, 3, 4, 5]
2.3 字典(Dictionary)
字典是一种键值对的数据结构,支持高效的查找、插入和删除操作。
- 创建字典
# 创建空字典
dic = {}
# 创建包含键值对的字典
dic = {"apple": 2, "banana": 1, "orange": 3}
# 使用 dict() 函数创建字典
dic = dict(apple=2, banana=1, orange=3)
- 访问元素
# 访问指定键对应的值
dic = {"apple": 2, "banana": 1, "orange": 3}
print(dic["apple"]) # 输出: 2
# 使用 get() 方法访问值(不存在时返回默认值)
print(dic.get("grape", 0)) # 输出: 0
- 添加或修改元素
# 添加新键值对
dic["grape"] = 5
print(dic) # 输出: {'apple': 2, 'banana': 1, 'orange': 3, 'grape': 5}
# 修改现有键对应的值
dic["apple"] = 10
print(dic) # 输出: {'apple': 10, 'banana': 1, 'orange': 3, 'grape': 5}
- 删除元素
# 删除指定键对应的项
del dic["banana"]
print(dic) # 输出: {'apple': 10, 'orange': 3, 'grape': 5}
# 使用 pop() 方法删除并返回值
value = dic.pop("orange")
print(value) # 输出: 3
print(dic) # 输出: {'apple': 10, 'grape': 5}
# 清空字典
dic.clear()
print(dic) # 输出: {}
- 遍历字典
# 遍历键
for key in dic:
print(key)
# 遍历值
for value in dic.values():
print(value)
# 遍历键值对
for key, value in dic.items():
print(key, value)
2.4 集合(Set)
集合是一个无序且不重复的元素集合,支持交集、并集、差集等操作。
- 创建集合
# 创建空集合
s = set()
# 创建包含元素的集合
s = {1, 2, 3, 4, 5}
# 使用 set() 函数创建集合
s = set([1, 2, 3, 4, 5])
- 添加元素
# 添加单个元素
s = {1, 2, 3}
s.add(4)
print(s) # 输出: {1, 2, 3, 4}
# 添加多个元素
s.update([5, 6])
print(s) # 输出: {1, 2, 3, 4, 5, 6}
- 删除元素
# 删除指定元素
s = {1, 2, 3, 4, 5}
s.remove(3)
print(s) # 输出: {1, 2, 4, 5}
# 如果元素不存在则抛出异常,使用 discard() 方法不会抛出异常
s.discard(6)
print(s) # 输出: {1, 2, 4, 5}
# 弹出任意元素
elem = s.pop()
print(elem) # 输出: 任意一个元素
print(s) # 输出: 剩余的元素
- 集合操作
# 交集
s1 = {1, 2, 3}
s2 = {2, 3, 4}
intersection = s1.intersection(s2)
print(intersection) # 输出: {2, 3}
# 并集
union = s1.union(s2)
print(union) # 输出: {1, 2, 3, 4}
# 差集
difference = s1.difference(s2)
print(difference) # 输出: {1}
# 对称差集
symmetric_difference = s1.symmetric_difference(s2)
print(symmetric_difference) # 输出: {1, 4}
2.5 优先队列(Heapq)
优先队列是一种特殊的队列,能够高效地获取最小或最大元素。Python 中可以使用 heapq
模块来实现优先队列。
- 创建堆
import heapq
# 创建空堆
heap = []
# 创建包含元素的堆
heap = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
heapq.heapify(heap)
print(heap) # 输出: [0, 2, 1, 6, 3, 5, 4, 7, 8, 9]
- 插入元素
# 插入元素
heapq.heappush(heap, 10)
print(heap) # 输出: [0, 2, 1, 6, 3, 5, 4,7, 8, 9, 10]
# 插入元素并保持堆的大小不变(替换最小元素)
heapq.heappushpop(heap, -1)
print(heap) # 输出: [-1, 2, 1, 6, 3, 5, 4, 7, 8, 9]
7, 8, 9, 10]
# 插入元素并保持堆的大小不变(替换最小元素)
heapq.heappushpop(heap, -1)
print(heap) # 输出: [-1, 2, 1, 6, 3, 5, 4, 7, 8, 9]
- 弹出最小元素
# 弹出最小元素
min_element = heapq.heappop(heap)
print(min_element) # 输出: -1
print(heap) # 输出: [0, 2, 1, 6, 3, 5, 4, 7, 8, 9]
- 获取 n 个最小/最大元素
# 获取 3 个最小元素
smallest_three = heapq.nsmallest(3, heap)
print(smallest_three) # 输出: [0, 1, 2]
# 获取 3 个最大元素
largest_three = heapq.nlargest(3, heap)
print(largest_three) # 输出: [9, 8, 7]
三、Python 的语法特性
3.1 语法糖(Syntactic Sugar)
Python 提供了许多简洁且高效的语法糖,使得代码更加易读和简洁。
- 列表推导式(List Comprehension)
# 使用 for 循环创建列表
lst = []
for i in range(10):
lst.append(i * i)
print(lst) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 使用列表推导式创建列表
lst = [i * i for i in range(10)]
print(lst) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的列表推导式
lst = [i * i for i in range(10) if i % 2 == 0]
print(lst) # 输出: [0, 4, 16, 36, 64]
- 字典推导式(Dictionary Comprehension)
# 使用 for 循环创建字典
dic = {}
for i in range(5):
dic[i] = i * i
print(dic) # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 使用字典推导式创建字典
dic = {i: i * i for i in range(5)}
print(dic) # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
- 集合推导式(Set Comprehension)
# 使用 for 循环创建集合
s = set()
for i in range(10):
s.add(i * i)
print(s) # 输出: {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
# 使用集合推导式创建集合
s = {i * i for i in range(10)}
print(s) # 输出: {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
- 生成器表达式(Generator Expression)
# 使用 for 循环创建生成器
gen = (i * i for i in range(10))
for num in gen:
print(num, end=" ") # 输出: 0 1 4 9 16 25 36 49 64 81
# 生成器表达式可以节省内存,因为它不会一次性生成所有元素
- 多重赋值
# 多重赋值
a, b, c = 1, 2, 3
print(a, b, c) # 输出: 1 2 3
# 交换两个变量的值
a, b = b, a
print(a, b) # 输出: 2 1
- 解包(Unpacking)
# 解包元组
tup = (1, 2, 3)
a, b, c = tup
print(a, b, c) # 输出: 1 2 3
# 忽略部分元素
a, *rest = (1, 2, 3, 4, 5)
print(a, rest) # 输出: 1 [2, 3, 4, 5]
# 解包字典
dic = {"name": "Alice", "age": 25, "city": "Beijing"}
name, age, city = dic.values()
print(name, age, city) # 输出: Alice 25 Beijing
- 链式比较
# 链式比较
x = 5
print(1 < x < 10) # 输出: True
print(1 < x and x < 10) # 等价于上面的链式比较
- 三元运算符
# 三元运算符
x = 5
result = "even" if x % 2 == 0 else "odd"
print(result) # 输出: odd
- 枚举(enumerate)
# 使用 for 循环遍历索引和元素
lst = ["apple", "banana", "orange"]
for i in range(len(lst)):
print(i, lst[i])
# 使用 enumerate() 函数简化代码
for i, item in enumerate(lst):
print(i, item)
- zip() 函数
# 合并两个列表
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
# 使用 for 循环合并
for i in range(len(names)):
print(names[i], ages[i])
# 使用 zip() 函数简化代码
for name, age in zip(names, ages):
print(name, age)
# 不同长度的列表会自动截断到最短长度
shorter = ["Alice", "Bob"]
longer = [25, 30, 35]
for name, age in zip(shorter, longer):
print(name, age)
3.2 Python 的优势
Python 在算法竞赛中有许多独特的优势,以下是一些常见的优势:
- 整形不会溢出:Python 中的整数类型没有固定的大小限制,可以表示任意大的整数。这在处理大数问题时非常方便。
# 计算大数的阶乘
import math
print(math.factorial(100)) # 输出: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
- 内置函数丰富:Python 提供了大量内置函数,可以直接使用而无需自己实现。
# 统计字符串中每个字符出现的次数
from collections import Counter
s = "hello world"
counter = Counter(s)
print(counter) # 输出: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
- 代码简洁易读:Python 的语法简洁,代码可读性强,减少了出错的可能性。
# 计算斐波那契数列的前 n 项
def fibonacci(n):
a, b = 0, 1
result = []
while len(result) < n:
result.append(a)
a, b = b, a + b
return result
print(fibonacci(10)) # 输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
- 动态类型系统:Python 是动态类型语言,变量不需要声明类型,编写代码更加灵活。
# 动态类型示例
x = 5
print(x) # 输出: 5
x = "Hello"
print(x) # 输出: Hello
- 丰富的标准库:Python 标准库提供了大量的模块和函数,可以直接使用这些工具来解决问题。
# 使用 bisect 模块进行二分查找
import bisect
lst = [1, 3, 5, 7, 9]
index = bisect.bisect_left(lst, 5)
print(index) # 输出: 2
# 插入元素并保持有序
bisect.insort(lst, 4)
print(lst) # 输出: [1, 3, 4, 5, 7, 9]
四、自带的算法库
Python 自带了许多常用的算法库,可以直接使用这些库来提高解题效率。
4.1 排序算法
Python 内置的 sorted()
函数和 list.sort()
方法可以对列表进行排序,默认是升序排序,也可以指定降序或自定义排序规则。
- 基本排序
# 升序排序
lst = [3, 1, 4, 1, 5, 9]
sorted_lst = sorted(lst)
print(sorted_lst) # 输出: [1, 1, 3, 4, 5, 9]
# 降序排序
sorted_lst = sorted(lst, reverse=True)
print(sorted_lst) # 输出: [9, 5, 4, 3, 1, 1]
# 使用 list.sort() 方法原地排序
lst.sort()
print(lst) # 输出: [1, 1, 3, 4, 5, 9]
- 自定义排序规则
# 按绝对值排序
lst = [3, -1, 2, -4, 5]
sorted_lst = sorted(lst, key=abs)
print(sorted_lst) # 输出: [-1, 2, 3, -4, 5]
# 按字符串长度排序
words = ["apple", "banana", "orange", "grape"]
sorted_words = sorted(words, key=len)
print(sorted_words) # 输出: ['grape', 'apple', 'banana', 'orange']
# 按多个条件排序
students = [("Alice", 25), ("Bob", 30), ("Charlie", 25)]
sorted_students = sorted(students, key=lambda x: (x[1], x[0]))
print(sorted_students) # 输出: [('Alice', 25), ('Charlie', 25), ('Bob', 30)]
4.2 查找算法
Python 提供了多种查找算法,如二分查找等。
- 二分查找
# 使用 bisect 模块进行二分查找
import bisect
lst = [1, 3, 5, 7, 9]
index = bisect.bisect_left(lst, 5)
print(index) # 输出: 2
# 插入元素并保持有序
bisect.insort(lst, 4)
print(lst) # 输出: [1, 3, 4, 5, 7, 9]
4.3 数学运算
Python 提供了丰富的数学运算函数,可以直接使用这些函数来进行复杂的数学计算。
- 常用数学函数
import math
# 绝对值
print(abs(-5)) # 输出: 5
# 最大值
print(max(1, 2, 3)) # 输出: 3
# 最小值
print(min(1, 2, 3)) # 输出: 1
# 四舍五入
print(round(3.7)) # 输出: 4
# 向上取整
print(math.ceil(3.2)) # 输出: 4
# 向下取整
print(math.floor(3.7)) # 输出: 3
# 开方
print(math.sqrt(16)) # 输出: 4.0
# 对数
print(math.log(10)) # 输出: 2.302585092994046
# 三角函数
print(math.sin(math.pi / 2)) # 输出: 1.0
- 随机数生成
import random
# 生成一个随机整数
print(random.randint(1, 10)) # 输出: [1, 10] 之间的随机整数
# 生成一个随机浮点数
print(random.random()) # 输出: [0, 1) 之间的随机浮点数
# 从列表中随机选择一个元素
lst = [1, 2, 3, 4, 5]
print(random.choice(lst)) # 输出: 列表中的一个随机元素
# 打乱列表顺序
random.shuffle(lst)
print(lst) # 输出: 打乱后的列表
五、Python 独有的技巧
5.1 字符串操作技巧
Python 的字符串操作非常强大,掌握一些技巧可以提高解题效率。
- 字符串反转
# 使用切片反转字符串
s = "hello"
reversed_s = s[::-1]
print(reversed_s) # 输出: olleh
- 字符串去重
# 使用集合去重
s = "hello"
unique_chars = "".join(set(s))
print(unique_chars) # 输出: ehol(注意:集合无序,结果可能不同)
# 保持顺序去重
from collections import OrderedDict
s = "hello"
unique_chars = "".join(OrderedDict.fromkeys(s))
print(unique_chars) # 输出: helo
- 字符串分割与拼接
# 分割字符串
s = "apple,banana,orange"
fruits = s.split(',')
print(fruits) # 输出: ['apple', 'banana', 'orange']
# 拼接字符串
joined_string = ",".join(fruits)
print(joined_string) # 输出: apple,banana,orange
5.2 列表操作技巧
Python 的列表操作也非常灵活,掌握一些技巧可以简化代码。
- 列表反转
# 使用 reverse() 方法反转列表
lst = [1, 2, 3, 4, 5]
lst.reverse()
print(lst) # 输出: [5, 4, 3, 2, 1]
# 使用切片反转列表
reversed_lst = lst[::-1]
print(reversed_lst) # 输出: [5, 4, 3, 2, 1]
- 列表去重
# 使用集合去重
lst = [1, 2, 2, 3, 4, 4, 5]
unique_lst = list(set(lst))
print(unique_lst) # 输出: [1, 2, 3, 4, 5](注意:集合无序,结果可能不同)
# 保持顺序去重
from collections import OrderedDict
lst = [1, 2, 2, 3, 4, 4, 5]
unique_lst = list(OrderedDict.fromkeys(lst))
print(unique_lst) # 输出: [1, 2, 3, 4, 5]
- 列表切片
# 获取子列表
lst = [1, 2, 3, 4, 5]
sub_lst = lst[1:4]
print(sub_lst) # 输出: [2, 3, 4]
# 获取每隔一个元素的子列表
every_other = lst[::2]
print(every_other) # 输出: [1, 3, 5]
# 反转列表
reversed_lst = lst[::-1]
print(reversed_lst) # 输出: [5, 4, 3, 2, 1]
5.3 其他技巧
- 惰性求值
# 使用生成器表达式实现惰性求值
gen = (i * i for i in range(10))
for num in gen:
print(num, end=" ") # 输出: 0 1 4 9 16 25 36 49 64 81
# 生成器表达式可以节省内存,因为它不会一次性生成所有元素
- 装饰器
# 定义一个简单的装饰器
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello")
say_hello()
# 输出:
# Before function call
# Hello
# After function call
- 上下文管理器
# 使用 with 语句管理资源
with open('example.txt', 'w') as file:
file.write('Hello, World!')
# 文件会在 with 语句块结束后自动关闭
# 自定义上下文管理器
class MyContextManager:
def __enter__(self):
print("Entering context")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting context")
with MyContextManager() as manager:
print("Inside context")
# 输出:
# Entering context
# Inside context
# Exiting context
六、Python 算法竞赛中的优化技巧
6.1 时间复杂度优化
在算法竞赛中,时间复杂度是衡量算法效率的重要指标。以下是一些常见的优化技巧:
- 避免不必要的循环嵌套
# 不推荐:双重循环导致 O(n^2) 复杂度
lst = [1, 2, 3, 4, 5]
for i in range(len(lst)):
for j in range(i + 1, len(lst)):
print(lst[i], lst[j])
# 推荐:使用组合生成器简化代码并提高效率
from itertools import combinations
for pair in combinations(lst, 2):
print(pair)
- 使用内置函数和库
# 不推荐:手动实现排序
lst = [3, 1, 4, 1, 5, 9]
sorted_lst = []
while lst:
min_val = min(lst)
sorted_lst.append(min_val)
lst.remove(min_val)
# 推荐:使用内置的 sorted() 函数
sorted_lst = sorted(lst)
- 缓存计算结果(Memoization)
# 不推荐:每次递归都重新计算斐波那契数列
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 推荐:使用缓存减少重复计算
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 输出: 55
6.2 空间复杂度优化
空间复杂度同样重要,尤其是在处理大规模数据时。以下是一些常见的优化技巧:
- 使用生成器代替列表
# 不推荐:创建一个大列表占用大量内存
large_list = [i * i for i in range(10**6)]
# 推荐:使用生成器表达式节省内存
large_gen = (i * i for i in range(10**6))
for num in large_gen:
print(num, end=" ")
- 原地修改数据结构
# 不推荐:创建新的列表进行排序
lst = [3, 1, 4, 1, 5, 9]
sorted_lst = sorted(lst)
# 推荐:使用 list.sort() 方法原地排序
lst.sort()
- 使用集合去重
# 不推荐:使用列表去重可能导致 O(n^2) 复杂度
lst = [1, 2, 2, 3, 4, 4, 5]
unique_lst = []
for item in lst:
if item not in unique_lst:
unique_lst.append(item)
# 推荐:使用集合去重,时间复杂度为 O(n)
unique_set = set(lst)
unique_lst = list(unique_set)
6.3 并行与多线程
虽然 Python 的 GIL(全局解释器锁)限制了多线程的性能提升,但在某些场景下仍然可以利用多进程或异步编程来加速任务。
- 多进程
# 使用 multiprocessing 模块实现多进程
import multiprocessing
def worker(num):
"""模拟耗时任务"""
print(f"Worker {num} is working")
if __name__ == "__main__":
processes = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
- 异步编程
# 使用 asyncio 实现异步编程
import asyncio
async def fetch_data():
print("Fetching data...")
await asyncio.sleep(1) # 模拟网络请求
print("Data fetched")
async def main():
tasks = [fetch_data() for _ in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())