给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
分析:求集合的所有子集问题。题目要求子集中元素非递减序排列,因此我们先要对原来的集合进行排序。原集合中每一个元素在子集中有两种状态:要么存在、要么不存在。这样构造子集的过程中每个元素就有两种选择方法:选择、不选择,因此可以构造一颗二叉树,例如对于例子中给的集合[1,2,3],构造的二叉树如下(左子树表示选择该层处理的元素,右子树不选择),最后得到的叶子节点就是子集:
class Solution {
private:
vector<vector<int> >res;
public:
vector<vector<int> > subsets(vector<int> &S)
{
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
//先排序,然后dfs每个元素选或者不选,最后叶子节点就是所有解
res.clear();
sort(S.begin(), S.end());
vector<int>tmpres;
dfs(S, 0, tmpres);
return res;
}
void dfs(vector<int> &S, int iend, vector<int> &tmpres)
{
if(iend == S.size())
{
res.push_back(tmpres);
return;
}
tmpres.push_back(S[iend]); //选择S[iend]
dfs(S, iend+1, tmpres);
tmpres.pop_back();
dfs(S, iend+1, tmpres); //不选择S[iend]
}
};
算法2:
从上面的二叉树可以观察到,当前层的集合 = 上一层的集合 + 上一层的集合加入当前层处理的元素得到的所有集合(其中树根是空集),因此可以从第二层开始(第一层是空集合)迭代地求最后一层的所有集合(即叶子节点),代码如下:
class Solution {
public:
vector<vector<int> > subsets(vector<int> &S)
{
vector<vector<int> > res(1);
sort(S.begin(), S.end());
for (int i = 0; i < S.size(); ++i)
{
int size = res.size();
for (int j = 0; j < size; ++j)
{
res.push_back(res[j]);
res.back().push_back(S[i]);
}
}
return res;
}
};
算法三:
整个添加的顺序为:
[]
[1]
[1 2]
[1 2 3]
[1 3]
[2]
[2 3]
[3]
class Solution {
public:
vector<vector<int> > subsets(vector<int> &S)
{
vector<vector<int> > res;
vector<int> out;
sort(S.begin(), S.end());
getSubsets(S, 0, out, res);
return res;
}
void getSubsets(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]);
getSubsets(S, i + 1, out, res);
out.pop_back();
}
}
};
参考资料