问题求解 · #9 / 11

复杂度 + 内存模型

大 O、可变性与拷贝

为什么重要

速度和空间,正是区分"被接受的解"和"超时(TLE)的解"的关键。

核心思想

要以每单位输入规模的操作数来思考。list.append() 是均摊 O(1);list.insert(0, x) 是 O(n),因为后面的一切都要移位。set / dict 的查找是 O(1);list 的成员检测(x in lst)是 O(n)。

亲眼看看 O(n²)

冒泡排序比较每一对相邻元素,并在每一趟中把最大的元素冒泡到末尾。点击 Auto 并数一数:24 个元素大约需要 200 次比较。翻倍到 48 个并不会只多花 2 倍——而是大约 4 倍。这就是 O(n²) 的样子。

comparisons: 0 swaps: 0

试一试

测一测 listset 成员检测之间的差距:

import time

N = 50000
data = list(range(N))
data_set = set(data)
needles = [N - 1, N // 2, 0]

t0 = time.perf_counter()
hits_list = sum(1 for x in needles if x in data)
t1 = time.perf_counter()
hits_set = sum(1 for x in needles if x in data_set)
t2 = time.perf_counter()

print(f"list lookups: {hits_list}  time: {(t1-t0)*1e6:.1f} µs")
print(f"set  lookups: {hits_set}  time: {(t2-t1)*1e6:.1f} µs")
not loaded

浅拷贝与深拷贝——可变对象总会让人意外:

import copy

grid = [[0] * 3 for _ in range(3)]
shallow = list(grid)       # same inner lists!
deep = copy.deepcopy(grid)

shallow[0][0] = 99
deep[0][0] = -1

print("grid    :", grid)
print("shallow :", shallow)
print("deep    :", deep)
not loaded

就地修改与新对象:

# sorted() makes a new list, sort() mutates in place
nums = [3, 1, 4, 1, 5]
asc = sorted(nums)         # new
nums.sort(reverse=True)    # in place
print("asc :", asc)
print("nums:", nums)
not loaded

快速检查

小练习

常见错误

关键要点