题目描述
思路解析动画文字版
思路一句话:从 start 往后选(升序去重),凑够 k 个就收集,剩数不够补满就剪枝。下面一步步演给你看。
选数字 1(下标 0)。还需选 1 个,下一层只能从它右边(下标 1)继续,这样组合天然升序、不会重复。
选数字 2(下标 1)。还需选 0 个,下一层只能从它右边(下标 2)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [1, 2]。这是第 1 个答案。
回退:撤销 2,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
选数字 3(下标 2)。还需选 0 个,下一层只能从它右边(下标 3)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [1, 3]。这是第 2 个答案。
回退:撤销 3,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
选数字 4(下标 3)。还需选 0 个,下一层只能从它右边(下标 4)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [1, 4]。这是第 3 个答案。
回退:撤销 4,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
回退:撤销 1,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
选数字 2(下标 1)。还需选 1 个,下一层只能从它右边(下标 2)继续,这样组合天然升序、不会重复。
选数字 3(下标 2)。还需选 0 个,下一层只能从它右边(下标 3)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [2, 3]。这是第 4 个答案。
回退:撤销 3,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
选数字 4(下标 3)。还需选 0 个,下一层只能从它右边(下标 4)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [2, 4]。这是第 5 个答案。
回退:撤销 4,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
回退:撤销 2,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
选数字 3(下标 2)。还需选 1 个,下一层只能从它右边(下标 3)继续,这样组合天然升序、不会重复。
选数字 4(下标 3)。还需选 0 个,下一层只能从它右边(下标 4)继续,这样组合天然升序、不会重复。
path 已凑满 2 个 → 收集组合 [3, 4]。这是第 6 个答案。
回退:撤销 4,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
回退:撤销 3,把它从 path 拿掉,换右边的数再试(这就是「回溯」——试完一条路就退回来换下一条)。
剪枝 ✗:还需 2 个,但从下标 3 往后只剩 1 个,凑不满了,直接砍掉这一支,省去无用搜索。
搜索结束:共找到 6 个组合。回溯就是「选一个→往深搜→退回来换下一个」,配合 start 升序和剪枝,不重不漏。
边界先想清。
两个高频追问。
参考代码
def combine(n, k): res, path = [], [] def bt(start): if len(path) == k: res.append(path[:]); return # 剪枝:剩余不够补满 k 个就停 for i in range(start, n - (k - len(path)) + 2): path.append(i) bt(i + 1) path.pop() bt(1) return res复杂度
- 时间:O(C(n,k)·k),共 C(n,k) 个组合,每个拷贝 k 个数
- 空间:O(k),递归深度 + path 长度都是 k
易错点
面试追问把动画讲成自己的话
追问组合和排列回溯的区别?
追问剪枝的上界怎么推的?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
子集
LeetCode 78 · 中等 · 沿着 回溯套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题