题目:
思路:
启动阶段:初始化空结果集 res,调用回溯函数 backtrack([], 0),以空路径为起点,从数组第0个元素开始遍历选择
递归遍历阶段:进入回溯函数后,先将当前路径副本存入 res,再从 start 索引开始遍历数组元素,依次执行“选元素→递归调用→撤销选择”的循环
回溯探索阶段:每次递归调用将 start 索引+1,限制后续选择范围,递归返回后通过 pop() 撤销选择,切换到“不选当前元素”的分支继续遍历
终止与收尾阶段:当遍历索引超出数组长度时,递归自然终止,所有分支遍历完成后,res 已收集全部子集,最终返回 res
代码:
class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: res = [] def backtrack(path,start): res.append(path.copy()) for i in range(start,len(nums)): path.append(nums[i]) backtrack(path,i+1) path.pop() backtrack([],0) return res例子:
以nums = [1,2,3]为例,一步步拆解回溯法的执行过程
回溯函数的两个关键参数:
path:当前已选中的元素start:当前开始遍历的索引(避免重复选,比如选了 2 就不再回头选 1)。
核心规则:每次进入回溯函数,先把当前path加入结果集(哪怕是空集),再遍历start到末尾的元素,依次做 “选” 或 “不选” 的决策。
步骤 1:初始调用backtrack([], 0)
此时path = [],start = 0。
- 第一步:把
[]加入结果集(结果集现在:[[]]); - 第二步:遍历
i = 0,1,2(对应元素 1、2、3),先处理i=0(元素 1)。
决策 1:选元素 1
path变为[1],递归调用backtrack([1], 1)(start变为 1,因为下一个只能选 2、3)。
步骤 2:执行backtrack([1], 1)
此时path = [1],start = 1。
- 第一步:把
[1]加入结果集(结果集:[ [], [1] ]); - 第二步:遍历
i = 1,2(对应元素 2、3),先处理i=1(元素 2)。
决策 2:选元素 2
path变为[1,2],递归调用backtrack([1,2], 2)(start变为 2,下一个只能选 3)。
步骤 3:执行backtrack([1,2], 2)
此时path = [1,2],start = 2。
- 第一步:把
[1,2]加入结果集(结果集:[ [], [1], [1,2] ]); - 第二步:遍历
i = 2(对应元素 3),处理i=2(元素 3)。
决策 3:选元素 3
path变为[1,2,3],递归调用backtrack([1,2,3], 3)(start变为 3,超出数组长度)。
步骤 4:执行backtrack([1,2,3], 3)
此时start = 3,超出数组长度(len(nums)=3),遍历循环不执行。
- 第一步:把
[1,2,3]加入结果集(结果集:[ [], [1], [1,2], [1,2,3] ]); - 第二步:无遍历,递归返回。
回溯:撤销 “选 3” 的决策
回到backtrack([1,2], 2),执行path.pop(),path变回[1,2];
- 遍历
i=2处理完毕,无更多i,递归返回。
回溯:撤销 “选 2” 的决策
回到backtrack([1], 1),执行path.pop(),path变回[1];
- 继续处理遍历的下一个
i=2(元素 3)。
步骤 5:回到backtrack([1], 1),处理i=2(元素 3)
决策 4:选元素 3
path变为[1,3],递归调用backtrack([1,3], 3)(start=3)。
执行backtrack([1,3], 3)
- 第一步:把
[1,3]加入结果集(结果集:[ [], [1], [1,2], [1,2,3], [1,3] ]); - 第二步:无遍历,递归返回。
回溯:撤销 “选 3” 的决策
回到backtrack([1], 1),执行path.pop(),path变回[1];
- 遍历
i=1,2处理完毕,递归返回。
回溯:撤销 “选 1” 的决策
回到初始的backtrack([], 0),执行path.pop(),path变回[];
- 继续处理遍历的下一个
i=1(元素 2)。
步骤 6:初始调用处理i=1(元素 2)
决策 5:选元素 2
path变为[2],递归调用backtrack([2], 2)(start=2)。
执行backtrack([2], 2)
- 第一步:把
[2]加入结果集(结果集:[ [], [1], [1,2], [1,2,3], [1,3], [2] ]); - 第二步:遍历
i=2(元素 3),处理i=2。
决策 6:选元素 3
path变为[2,3],递归调用backtrack([2,3], 3)。
执行backtrack([2,3], 3)
- 第一步:把
[2,3]加入结果集(结果集:[ [], [1], [1,2], [1,2,3], [1,3], [2], [2,3] ]); - 第二步:无遍历,递归返回。
回溯:撤销 “选 3”→ 撤销 “选 2”
回到初始的backtrack([], 0),path变回[],继续处理i=2(元素 3)。
步骤 7:初始调用处理i=2(元素 3)
决策 7:选元素 3
path变为[3],递归调用backtrack([3], 3)。
执行backtrack([3], 3)
- 第一步:把
[3]加入结果集(最终结果集:[ [], [1], [1,2], [1,2,3], [1,3], [2], [2,3], [3] ]); - 第二步:无遍历,递归返回。
回溯:撤销 “选 3”
回到初始的backtrack([], 0),遍历结束,整个回溯过程完成。