描述
Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
分析1
要求写出集合的所有子集。
子集的生成过程是这样子的:对于原集合中的每个元素,都有两种状态,一种是放入子集中,另一种是不放入子集中,当我们决定了原来集合中所有元素的状态后,我们便确定了一个子集。
对于元素个数为
n
的集合,共有
[]
/ \
/ \
/ \
[] [1]
/ \ / \
/ \ / \
[] [2] [1] [1 2]
/ \ / \ / \ / \
[] [3] [2] [2 3] [1] [1 3] [1 2] [1 2 3]
根据这个思路,我们能写出递归的代码出来,如下所示。
代码1
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> tmp;
sort(nums.begin(), nums.end());
getSubsets(nums, 0, tmp, res);
return res;
}
void getSubsets(vector<int>& nums, int i, vector<int> tmp, vector<vector<int>>& res) {
if (i == nums.size()) {res.push_back(tmp); return;}
getSubsets(nums, i + 1, old, res);
tmp.push_back(nums[i]);
getSubsets(nums, i + 1, tmp, res);
}
};
getSubsets 函数:在当前节点为 tmp 的情况下,处理原来集合 nums 的第 i 个元素。
分析2
另外一种递归的写法,思路大同小异。
代码2
class Solution {
public:
vector<vector<int>> subsets(vector<int>& S) {
sort(S.begin(), S.end());
vector<vector<int>> res; vector<int> out;
toSet(S, 0, out, res);
return res;
}
void toSet(vector<int>& S, int pos, vector<int>& out, vector<vector<int>>& res) {
res.push_back(out);
for (int i = pos; i < S.size(); i++) {
out.push_back(S[i]);
toSet(S, i + 1, out, res);
out.pop_back();
}
}
};
分析3
还是上面的思路,换一种思考方式,假设我们现在已经有了前
1. 不添加进子集,这种情况下的
2i
个子集就是
Si
。
2. 添加进子集,这种情况下就是把这个元素添加进
Si
里每个集合。
因此我们可以首先把空集放入
res
中,然后遍历
nums
所有元素,对于每个元素,将当前
res
中的所有集合添上这个元素,然后放入
res
中。以集合 [1,2,3] 为例子,步骤如下:
处理前res | 处理的元素 | 处理后res |
---|---|---|
[ ] | 1 | [ ],[1] |
[ ],[1] | 2 | [ ],[1],[2],[1 2] |
[ ],[1],[2],[1 2] | 3 | [ ],[1],[2],[1 2],[3],[1 3],[2 3],[1 2 3] |
代码3
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res(1);
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
int size = res.size();
for (int j = 0; j < size; j++) {
res.push_back(res[j]);
res[size + j].push_back(nums[i]);
}
}
return res;
}
};
分析4
另外一种思路,我们将每个元素的两种状态用
0,1
来表示,那么一个
n
个元素的集合的子集就对应了一个
代码4
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
int n = 1 << nums.size();
for (int i = 0; i < n; i++)
res.push_back(toSet(nums, i));
return res;
}
vector<int> toSet(vector<int>& nums, int k) {
vector<int> res;
for (int i = 0; i < nums.size(); i++, k = k >> 1) {
if (k % 2 == 1) res.push_back(nums[i]);
}
return res;
}
};