原题见leetcode的subSets和subsetsWithDup,本篇文章着重采用“增量构造法”,解决此类问题。当然,还有其他办法,如递归法、位向量法等。
首先看subSets题目:https://oj.leetcode.com/problems/subsets/,描述如下:
Given a set of distinct integers, S, return all possible subsets.
Note:
For example,
If S = [1,2,3]
, a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]采取增量构造法,意味着首先声明一个vector<vector<int> > 的变量res,首先res需要插入一个空的元素,然后每次读取res的元素个数,插入与其元素个数相同的元素。
如第一次,res.size() = 1,那么只插入一个元素;第二次,res.size() = 2,插入2个,故每次分别插入1、2、4、8...个元素。代码如下:
void subSetNoDup(vector<int> s, vector<vector<int> > &res)
{
if(s.empty())
return;
sort(s.begin(), s.end());
res.clear();
res.resize(1);
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的末尾插入相同元素 */
res.back().push_back(s[i]); /* 在新插入的元素里,加入新的子元素 */
}
}
}
然后有此题目的变种:subsetsWithDup:https://oj.leetcode.com/problems/subsets-ii/,描述如下:
Given a collection of integers that might contain duplicates, S, return all possible subsets.
Note:
For example,
If S = [1,2,2]
, a solution is:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]此时,数组中存在重复元素,需要“去重”。思路是:设prev是前一个元素,nxt是prev的下一个元素,且两者相等;那么在已经插入prev的前提下,nxt只有一种选择:一、和prev在一起,构造新的元素。意思就是,在之前的元素里,如不存在prev,那么nxt必须跳过这些元素。因此,需要记录上次res的元素个数,代码如下:
void subSetwithDup(vector<int> s, vector<vector<int> > &res)
{
if(s.empty())
return;
sort(s.begin(), s.end());
int previse_size = 0;
res.clear();
res.resize(1);
for(int i = 0; i < s.size(); i++)
{
int size = res.size();
for(int j = 0; j < size; j++)
{
if(i == 0 || s[i] != s[i-1] || j >= previse_size) /* 3中情况下,可插入当前元素,最后一种是上述情况 */
{
res.push_back(res[j]);
res.back().push_back(s[i]);
}
}
previse_size = size; /* 记录上一次res的元素个数 */
}
}