开始前应具备
- 掌握递归与调用栈
- 理解树的 DFS
- 能够区分路径状态和最终答案
CHAPTER 08 · 暴力搜索
把选择过程画成决策树,用选择、递归、撤销覆盖所有可能。
BEFORE LEARNING
回溯是有组织的暴力枚举。关键不是递归本身,而是把选择过程画成决策树,并确保每条路径只被访问一次。
开始前应具备
完成本章后
CORE LESSONS
LESSON
需要枚举所有合法方案、路径或组合,而且每一步都从若干选择中决定下一步。
路径保存已经做出的选择,选择列表给出当前可选项,结束条件决定何时收集答案。递归返回后撤销选择,让同层其他分支从相同状态开始。
def backtrack(path, choices):
if finished(path): collect(path); return
for choice in choices:
make(choice)
backtrack(path, next_choices)
undo(choice)LESSON
子集关心选或不选,组合不关心顺序,排列关心顺序。三者主要区别在下一层选择范围。
组合和子集使用 start 控制只能向后选择,从结构上避免重复;排列每层都可选择未使用元素,因此需要 used 数组。
# 组合
for i in range(start, n):
path.append(a[i])
backtrack(i + 1)
path.pop()LESSON
部分路径已经违反约束,或在网格中寻找不能重复使用格子的路径。
剪枝是在进入更深递归前排除必然失败的分支。网格搜索还需要标记当前路径已使用的格子,并在返回时恢复,允许其他起点重新使用。
if invalid(state): return
mark(choice)
for next in candidates: backtrack(next)
unmark(choice)READING
先读完本站讲义并尝试练习;遇到推导不清的地方,再回到原始教程深入阅读。
PRACTICE LADDER
题量由知识点决定,不再固定为 5 道。先完成“入门”和“模板”,再做变式与综合;挑战题可以留到复习阶段。
1 道 · 依次完成
Subsets
为什么选:每个元素选或不选,观察完整决策树。
3 道 · 依次完成
Combinations
为什么选:用 start 避免组合重复。
Permutations
为什么选:排列每层选择未使用元素,需要 used 状态。
Combination Sum
为什么选:元素可重复选择,下一层 start 不加一。
2 道 · 依次完成
Generate Parentheses
为什么选:通过左右括号数量提前剪掉非法前缀。
Word Search
为什么选:在网格路径中完成选择、标记、递归和恢复。
PERSONAL NOTEBOOK
笔记保存在当前浏览器