1、回溯
我们可以假设在每个节点上,我们都可以选择加入当前节点或者不加入当前节点,因此最终的结果可以构成一棵树,我们需要遍历整棵树的叶子节点并返回结果。因此我们可以使用回溯法来遍历整个树。
我们从位置0开始进行遍历,每次我们都先将当前节点加入最终结果中,并调用函数探索加入当前节点后的结果,如此递归直至当前位置等于字符串的长度为止。而后我们将当前的节点退出,并继续探索推出后下一个位置的情况。
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> track;
backtrack(nums, 0, track);
return res;
}
void backtrack(vector<int>& nums, int start, vector<int>& track) {
res.push_back(track);
for (int i = start; i < nums.size(); i++) {
track.push_back(nums[i]);
backtrack(nums, i + 1, track);
track.pop_back();
}
}
};
2、递归
具体思路同上,区别在于我们全部使用递归来探索加入与不加入的情况。
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;
void dfs(int cur, vector<int>& nums) {
if (cur == nums.size()) {
ans.push_back(t);
return;
}
t.push_back(nums[cur]);
dfs(cur + 1, nums);
t.pop_back();
dfs(cur + 1, nums);
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(0, nums);
return ans;
}
};
3、位运算实现枚举
我们可以使用长于位n的二进制串来表示每个数字的选择情况,最终将所有组合加入最终结果即可。
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if (mask & (1 << i)) {
t.push_back(nums[i]);
}
}
ans.push_back(t);
}
return ans;
}
};