90. Subsets II
Total Accepted: 65104 Total Submissions: 214320 Difficulty: Medium
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note:
- Elements in a subset must be in non-descending order.
- The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2]
, a solution is:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]
【分析】
这个题我思考了很久,感觉并没有非常好的解法,首先有几个回避不了的问题:
1、题目要求所有子集中的数据非降序排列,如此,对输入数据集进行排序不可避免,sort()可以解决,时间复杂度O(nlogn);
2、要求所有子集,以一个N个元素的数据集为例,其可能的子集数为:N(N+1)/2 +空集,因此,最差搜索时间复杂度O(n2);
3、出现重复数据,如何去重复?
思考良久,我还是采用了深度优先搜索(Deepth First Search,DFS),DFS方法可以搜索到指定深度的所有可行解。若不考虑空集,此题的深度范围[1,N],因此需要比普通的DFS增加一重循环;同时,考虑到去重复,需要在搜索过程中“剪枝”,这也是解决此题的关键,我简单叙述一下DFS中去重复(“剪枝”)的方法:对于一个数据集[1,2,2,2],如果深度为3(须三层搜索),即三个元素的子集,由于DFS本身结合递归和回溯的思想,对于任何一层搜索,若不考虑重复数据,则决不能出现重复数据,如:第二层第一次搜索得元素2,那么搜索到底回溯至第二层时,理论上应该对第二层进行第二次搜索,得元素2,但是这样明显重复了,为什么会重复呢?因为DFS每一层搜索事实上都是一种“穷举”的思想,因此,必须剪枝。
【解法及注释】
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums)
{
vector<vector<int>> result;
vector<int> temp;
if(nums.empty())return result;
sort(nums.begin(),nums.end());
result.push_back(temp);//存入空集
for(int i=1;i<=nums.size();i++)//深度搜索,深度分别为[1,N]
{
DFS(nums, result, temp, i,0);
}
return result;
}
private:
void DFS(vector<int>& nums,vector<vector<int>>& result,vector<int>& temp,int deepth,int start)
{
if(temp.size()==deepth)//搜索深度到达,存储可行解,返回上一层继续搜索
{
result.push_back(temp);
return;
}
else
{
for(int i=start;i<nums.size();i++)
{
if(i!=start&&nums[i]==nums[i-1])continue;//剪枝去重复,对于搜索的任何一层决不能在本层出现重复
temp.push_back(nums[i]);//存储到可行解路径中
DFS(nums, result, temp, deepth,i+1);//搜索下一层,注意其搜索起点i+1,避免数据重复使用
temp.pop_back();//某一层搜索结束顶层出栈,或者某一层数据搜索到可行解,继续该层下一次搜索
}
}
}
};