78. 子集
3 min
题目
解法:回溯枚举
思路
核心思想是回溯法(DFS)枚举所有组合。对每个元素,递归选择”选”或”不选”两种分支,遍历整棵决策树。
正确性源于对决策树的完整遍历。每次递归固定一个起始位置 start,确保元素不重复使用。将每个中间状态 path 都加入结果,覆盖了所有子集可能。递归深度为 n 时,恰好生成 2^n 个子集,无遗漏无重复。
- Step 1: 初始化结果集 ans 和当前路径 path
- Step 2: 调用 dfs(nums, 0, path, ans) 开始递归
- Step 3: 进入 dfs 立即将当前 path 加入 ans(记录所有访问节点)
- Step 4: 从 start 遍历到数组末尾
- Step 5: path.push_back(nums[i]) 选择当前元素
- Step 6: dfs(nums, i+1, path, ans) 递归处理后续元素
- Step 7: path.pop_back() 回溯,撤销选择
- Step 8: 返回 ans
复杂度
- 时间复杂度:
- 空间复杂度:
代码
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> ans;
vector<int> path;
dfs(nums, 0, path, ans);
return ans;
}
void dfs(const vector<int>& nums, int start, vector<int>& path, vector<vector<int>>& ans) {
// 1. 任何时候进入都把当前 path 加入结果
ans.push_back(path);
// 2. 尝试从 start 位置开始向后选择元素
for (int i = start; i < nums.size(); i++) {
path.push_back(nums[i]); // 选择
dfs(nums, i + 1, path, ans); // 递归
path.pop_back(); // 回溯
}
}
};