第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,使用递归栈