1. 题目来源
链接:78. 子集
必看,必刷,dfs 经典:
- [Mdfs] lc39. 组合总和(dfs+经典)
- [Mdfs] lc40. 组合总和 II(dfs+经典)
- [Mdfs] lc46. 全排列(dfs+经典)
- [Mdfs] lc47. 全排列 II(dfs搜索顺序+去重处理+知识理解+经典)
- [Mdfs] lc77. 组合(组合类型枚举+题目总结+经典)
- [Mdfs] lc78. 子集(二进制枚举+排列类型枚举+经典)
- [Mdfs] lc90. 子集 II(组合类型枚举+多重背包+去重经典)
2. 题目解析
回溯经典题目。
枚举每个数选不选即可,也可以直接用二进制枚举选不选也是一样的。
注意本题两种 dfs 的不同之处。dfs 递的过程中记录答案,dfs 归的过程中记录答案
时间复杂度: O ( n ∗ 2 n ) O(n*{2^n}) O(n∗2n),由于需要记录方案,看答案就懂了
空间复杂度: O ( n 2 ) O(n^2) O(n2)
归 过程写法:
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int>& a, int u) {
if (u == a.size()) {
res.push_back(path);
return ;
}
dfs(a, u + 1);
path.push_back(a[u]);
dfs(a, u + 1);
path.pop_back();
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums, 0);
return res;
}
};
递 过程写法
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int>& nums, int u) {
res.push_back(path);
for (int i = u; i < nums.size(); i ++ ) {
path.push_back(nums[i]);
dfs(nums, i + 1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums, 0);
return res;
}
};
二进制枚举,迭代写法:
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
int n = nums.size();
for (int i = 0; i < 1 << n; i ++ ) {
vector<int> path;
for (int j = 0; j < n; j ++ )
if (i >> j & 1)
path.push_back(nums[j]);
res.push_back(path);
}
return res;
}
};