题目描述(Medium)
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
题目链接
https://leetcode.com/problems/subsets-ii/description/
Example 1:
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
算法分析
方法一:dfs解法,时间复杂度,空间复杂度,注意到处理第三个元素2时,因为前面已经处理了一次2,所有第三层中,我们只在已经添加过2的集合{1,2}、{2}上再添加2,而没有在集合{1}, {}上添加2(画叉的分支),假设下面还有一个2,那么我们只在第四层的包含两个2的集合{1,2,2}、{2,2}上再添加2,其它都不添加。因此dfs时,如果当前处理的数字前面出现了k次,那么我们要处理的集合中必须包含k个该元素。
方法二:如果当前处理的元素没有出现过,则把前面得到的所有集合加上该元素;如果出现过,则只把上一轮处理的集合加上该元素。比如处理第二个2时(二叉树第三层),我们只把上一轮添加过数字的集合{1,2}、{2}再添加一个2加入结果中,{1}、{}是从上一层直接继承下来的,所以不作处理。时间复杂度,空间复杂度。
扫描二维码关注公众号,回复: 3741726 查看本文章算法参考自:LeetCode:Subsets I II
提交代码(方法一):
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> path;
vector<vector<int>> result;
dfs(nums, path, 0, result);
return result;
}
void dfs(vector<int>& nums, vector<int>& path,
int step, vector<vector<int>> &result) {
if (step == nums.size())
{
result.push_back(path);
return;
}
int firstSame = step;
while (firstSame >= 0 && nums[step] == nums[firstSame])
--firstSame;
int sameNum = step - firstSame - 1;
if (sameNum == 0 || (path.size() >= sameNum
&& path[path.size()- sameNum] == nums[step])) {
// 考虑S[i]
path.push_back(nums[step]);
dfs(nums, path, step + 1, result);
path.pop_back();
}
// 不考虑S[i]
dfs(nums, path, step + 1, result);
}
};
提交代码(方法二):
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
result.push_back(vector<int>());
int last = nums[0], opResNum = 1;
for (int i = 0; i < nums.size(); ++i) {
// 保留当前操作增加的子集数目
if (nums[i] != last)
{
last = nums[i];
// 此时集合数目,保留到下一次做差
opResNum = result.size();
}
int prev_size = result.size() - opResNum;
for (int j = result.size() - 1; j >= prev_size; --j) {
result.push_back(result[j]);
result.back().push_back(nums[i]);
}
}
return result;
}
};