第7章|回溯与搜索

Unit 05 · LeetCode #39 · 真实搜索树重构版

← Unit 04
39
Combination SumReusable · Remaining · Break

同一个候选可以重复使用,
但搜索顺序不能重新回头。

remaining 表示尚未填补的目标;选择候选后,递归仍从当前 index 开始,使它可以再次出现。排序后的 break 只拒绝候选,不会制造一个“失败递归节点”。

题目要求

给定互不相同的正整数数组 candidates 和目标值 target,返回所有和等于目标值的唯一组合。同一个候选可以被选择任意多次。

candidates = [2,3,6,7]\ntarget = 7\n答案 = [[2,2,3],[7]]

三个关键契约

sum(path) + remaining = target
可复用:backtrack(index, remaining - value)
已排序且 value > remaining → break
Remaining Target

remaining 归零时才记录;路径长度没有固定值。

Reusable Choice

递归继续传当前 index,使同一候选可再次使用。

Canonical Order

不回到更小索引,避免同一组合产生不同顺序。

Sorted Break

过大的候选只在候选窗口里被拒绝,不进入递归树。

真实搜索树|[2,3,6,7] → 7
绿色底边:remaining=0橙色:当前真实递归帧红色只出现在候选区:break,不是树节点
当前状态契约
当前路径和

当前 path

当前候选窗口

当前递归栈

current
start
remaining
扫描 index

事件记录

数值不变量

唯一性不变量

路径和
remaining
已识别答案
真实树节点
状态一致
渐隐脚手架完整演示 → 功能提示槽位 → 关键代码补全 → 独立完成
关键槽位补全先选左侧槽位 → 再选右侧代码
实时拼接后的代码骨架只拼接你已经建立的语义映射
当前认知焦点

此刻不应该提前改变
本行真正负责
代码 × 状态逐行联动
状态依赖问题|当前在 path=[2,2]、remaining=3 扫描 value=6。为什么执行的是 break,而不是进入一个“[2,2,6]”递归节点?

这只是理解检查,不会阻塞下一步或自动播放。

独立完成|关闭上方脚手架后,自行写出 #39

迁移题:LeetCode #40 组合总和 II

#39 的 remaining 与排序 break 保留;变化是:当前索引不能复用,递归改为 index+1,同时加入同层去重。

所有迁移步骤始终可进入

Unit 05 Skill 卡

真实搜索树只包含真正进入过递归的状态。#39 用 current index 表达候选复用,用 remaining 表达完成状态,用排序单调性表达 break;#40 再把“复用”改成“单次使用+同层去重”。

真实节点10 个递归状态
答案[2,2,3]、[7]
复用backtrack(index,...)
剪枝候选过大直接 break
#40index+1 + 同层去重
DFS无 queue,使用递归栈