算法竞赛中常以极端数据和数据量检验代码质量,一般写法很容易TLE或MLE,而Python标准库提供了很多功能强大的函数,我们可以用以下方式优化代码的时空复杂度:
输入
快速读取
1 2 3 4
| import sys data_1 = sys.stdin.read() data_2 = sys.stdin.readline() data_3 = sys.stdin.readlines()
|
列表推导式写法:
1
| data = [line for line in sys.stdin]
|
记忆递归
functools模块的lru_cache装饰器可实现记忆缓存功能,免去函数递归调用时的大量重复计算
以简单的阶乘和斐波那契数列为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from functools import lru_cache
@lru_cache(maxsize = None) def fact(n): if n == 1: return 1 else: return n*fact(n-1)
@lru_cache(maxsize = None) def fib(n): if n <= 2: return 1 else: return f(n-1) + f(n-2)
|
排列组合
itertools模块中的函数能高效实现为可迭代对象生成全排列/组合功能:
1 2 3 4 5 6 7 8 9
| import itertools
data = [1,2,3] perm_data = itertools.permutations(data,r = len(data))
comb_data = itertools.combinations(data,2)
comb_with_rep_data = itertools.combinations_with_replacement(data,a)
|
无限迭代
itertools模块中含有多个无限迭代器:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import itertools
for i in itertools.count(1,2): print(i)
for i in itertools.cycle([1,2,3,4]): print(i)
for i in itertools.repeat(1,4): print(i)
|
数学操作
math库作为Python数学专用标准库,集成了大量数学操作函数:
1 2 3 4 5 6 7 8 9 10
| import math
math.inf math.pi math.sqrt(x) math.pow(a,b) math.ceil(x) math.floor(x) math.gcd(m,n) math.factorial(n)
|
✅ 注意:math.gcd() 只返回非负数,且只支持两个数。
collections库
collections库提供了多个高效容器,在算法题中常用于计数、建图、队列和分组统计等场景。
Counter可以快速统计可迭代对象中每个元素出现的次数,访问不存在的键返回0而非KeyError:
1 2 3 4 5 6 7 8 9
| from collections import Counter
nums = [1, 2, 2, 3, 3, 3] cnt = Counter(nums)
print(cnt[1]) print(cnt[3]) print(cnt[4]) print(cnt.most_common(2))
|
常用操作:
1 2 3 4 5 6 7 8
| from collections import Counter
s = "abacaba" cnt = Counter(s) cnt["a"] += 1 cnt["b"] -= 1
elements = list(cnt.elements())
|
两个Counter之间支持加减运算:
1 2 3 4 5 6 7 8 9
| from collections import Counter
a = Counter("aab") b = Counter("abb")
print(a + b) print(a - b) print(a & b) print(a | b)
|
✅ 判断两个字符串是否为字母异位词,直接用Counter(a) == Counter(b)即可。
defaultdict可以为不存在的键自动创建默认值,常用于邻接表建图和分组:
1 2 3 4 5 6 7 8 9 10 11
| from collections import defaultdict
graph = defaultdict(list) edges = [(1, 2), (1, 3), (2, 4)]
for u, v in edges: graph[u].append(v) graph[v].append(u)
print(graph[1]) print(graph[5])
|
用于计数:
1 2 3 4 5 6 7 8
| from collections import defaultdict
cnt = defaultdict(int) nums = [1, 2, 2, 3, 3, 3] for x in nums: cnt[x] += 1
print(cnt)
|
用于分组:
1 2 3 4 5 6 7 8 9
| from collections import defaultdict
groups = defaultdict(list) words = ["apple", "ant", "banana", "boat"]
for word in words: groups[word[0]].append(word)
print(groups)
|
deque是双端队列,两端增删均为O(1),适合BFS、滑动窗口等场景:
1 2 3 4 5 6 7 8 9
| from collections import deque
q = deque() q.append(1) q.append(2) q.appendleft(0)
print(q.popleft()) print(q.pop())
|
BFS广度优先搜索模板:
1 2 3 4 5 6 7 8 9 10 11 12
| from collections import deque
def bfs(start, graph): q = deque([start]) vis = {start}
while q: u = q.popleft() for v in graph[u]: if v not in vis: vis.add(v) q.append(v)
|
带层数统计的BFS:
1 2 3 4 5 6 7 8 9 10 11 12 13
| from collections import deque
def bfs_level(start, graph): q = deque([start]) dist = {start: 0}
while q: u = q.popleft() for v in graph[u]: if v not in dist: dist[v] = dist[u] + 1 q.append(v) return dist
|
固定长度队列(自动淘汰旧元素):
1 2 3 4 5 6 7 8 9
| from collections import deque
q = deque(maxlen=3) q.append(1) q.append(2) q.append(3) q.append(4)
print(q)
|
✅ list在头部插入和删除是O(n),deque两端操作均为O(1),队列类问题优先考虑deque。
OrderedDict在需要调整键值位置时比普通dict更方便:
1 2 3 4 5 6 7 8 9 10 11 12
| from collections import OrderedDict
od = OrderedDict() od["a"] = 1 od["b"] = 2 od["c"] = 3
od.move_to_end("a") print(od)
od.popitem(last=True) od.popitem(last=False)
|
namedtuple可以创建轻量级的不可变数据对象,支持下标和属性两种访问方式:
1 2 3 4 5 6 7 8 9 10 11
| from collections import namedtuple
Point = namedtuple("Point", ["x", "y"]) p = Point(3, 4)
print(p.x) print(p[0])
Edge = namedtuple("Edge", ["u", "v", "w"]) e = Edge(1, 2, 5) print(e.u, e.v, e.w)
|
heapq库
heapq实现了最小堆(优先队列),可在O(log n)时间内插入和弹出最小值:
1 2 3 4 5 6 7 8 9 10
| import heapq
heap = [] heapq.heappush(heap, 5) heapq.heappush(heap, 1) heapq.heappush(heap, 3) heapq.heappush(heap, 7)
print(heapq.heappop(heap)) print(heapq.heappop(heap))
|
查看堆顶元素:
1 2 3 4 5 6
| import heapq
heap = [3, 1, 5, 2] heapq.heapify(heap)
print(heap[0])
|
Python只有最小堆,要模拟最大堆可以把值取负存入:
1 2 3 4 5 6 7 8 9 10
| import heapq
nums = [3, 1, 5, 2, 4] max_heap = []
for x in nums: heapq.heappush(max_heap, -x)
print(-heapq.heappop(max_heap)) print(-heapq.heappop(max_heap))
|
取最大/最小的K个元素:
1 2 3 4 5 6
| import heapq
nums = [3, 1, 5, 2, 4, 7, 6]
print(heapq.nlargest(3, nums)) print(heapq.nsmallest(3, nums))
|
堆排序:
1 2 3 4 5 6 7 8
| import heapq
def heap_sort(arr): heap = arr[:] heapq.heapify(heap) return [heapq.heappop(heap) for _ in range(len(heap))]
print(heap_sort([3, 1, 4, 1, 5, 9]))
|
合并多个有序序列:
1 2 3 4 5 6 7 8
| import heapq
a = [1, 4, 7] b = [2, 5, 8] c = [3, 6, 9]
merged = heapq.merge(a, b, c) print(list(merged))
|
✅ heapq默认是最小堆,需要最大堆时取负数入堆;nlargest/nsmallest适合K较小时的TopK问题。