题目描述
思路解析动画文字版
最直接的想法:每个候选数选几次都试一遍,再看哪些和正好等于 target。可这样既会重复(2+3 和 3+2 算两次),又不知道什么时候该停,一路加到超了还在加。
转折:维护一个「剩余 remain」。选了某个数,remain 就减它;remain==0 说明凑齐了,记录组合;remain<0 说明超了,剪枝回头。再用 start 下标只往后选避免重复——但因为允许重复选,递归时仍从当前数 i 开始(不前进到 i+1)。
选 2:先选 2,path=[2],remain = 7−2 = 5(大于 0,继续)。因为能重复,下一步仍可从 2 选起。
再选 2:又从 2 选起,再拿一个 2,path=[2,2],remain = 5−2 = 3。还没到 0,继续往下。
选 3 · 凑齐:这一层从 i=1(数字 3)选起,选 3,path=[2,2,3],remain = 3−3 = 0!凑齐了,记录组合 [2,2,3],然后回溯。
回 [2,2] 试 6 · remain<0 剪枝:负例分支:撤销 3 回到 [2,2](remain=3),for 前进试 6:remain = 3−6 = −3 小于 0,超了 → 剪枝、立刻返回,连递归都不进。试 7 也超,这条分支结束。
回 [2] 试 3:再撤一层回到 [2](remain=5)。「用 2」这支已试完(得到 [2,2,3]),for 前进到下一个候选 3:[2,3] remain=2,往下从 3 选起再选 3 超(2−3小于0)、选更大也超,剪枝。
回到空 · 换 3 打头:彻底撤回到空,for 前进换 3 打头(start=1,不再回头看 2,避免重复):[3] remain=4,再选 3 → [3,3] remain=1,此后任何候选(3/6/7)都 >1 → 剪;选 6 又 >4 → break。[3] 这支凑不出 7,撤掉。
换 6 打头 · 同样死路:再换 6 打头:[6] remain=1,但 start 锁定只能从 6 往后选,6、7 都比 1 大,remain 必为负 → 剪枝。继续前进到最后一个候选 7。
选 7 · 再收一条:选 7:remain = 7−7 = 0,记录 [7]。候选全试完,所有组合找齐:[[2,2,3], [7]],和示例对上。
把「凑数」变成「剩余目标递减」,到 0 就收、超了就剪——组合总和、目标和、分割等和子集都是这套带剪枝的回溯。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:先复用状态定义,再调整边界条件。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
参考代码
class Solution: def combinationSum(self, candidates, target): candidates.sort() ans = [] def backtrack(start, remain, path): if remain == 0: ans.append(path[:]) return for i in range(start, len(candidates)): x = candidates[i] if x > remain: break path.append(x) backtrack(i, remain - x, path) path.pop() backtrack(0, target, []) return ans复杂度
- 时间复杂度:≈ O(N^(T/min)),搜索树最深 T/min 层(每层最多 N 个分支),由解的数量与深度决定,剪枝大幅砍掉无效枝
- 空间复杂度:O(T/min),递归栈深 = path 最长长度 = target/最小候选数
可套用的代码模板
记住骨架:remain==0 收、remain<0 剪、可复用传 i 不可复用传 i+1。换「剩余量」的定义就能套一大类组合搜索。
def backtrack(start, remain, path): if remain == 0: res.append(path[:]); return for i in range(start, n): if c[i] > remain: break # 排序后剪枝 path.append(c[i]) backtrack(i, remain - c[i], path) # 传 i 可重复 / 传 i+1 不重复 path.pop()易错点
面试追问把动画讲成自己的话
追问为什么递归传 i 不传 i+1?
追问怎么避免重复组合([2,3]和[3,2])?
追问和「组合总和 II」差在哪?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
全排列
LeetCode 46 · 中等 · 沿着 回溯 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题