本题是力扣78的升级版,多了一个限制条件,就是集合里面会出现重复的元素,而且结果集里边不能有重复的子集,就比如集合{1,2,2}当中,返回的结果集可以包含集合{2,2}但是不能有两个{2,2}.因此我们需要考虑额外增加一个数组used,来记录这个元素是否被使用过,还需要用这个集合的元素来反映重复元素的去重情况。我们根据分析情况画出的树形图如下
我们从这张图中不难发现,我们需要先对集合排序,然后在处理节点。由于也是子集问题,每个节点都需要收集到结果集里边,而且由于是在同一个数组里边求集合,所以同样需要startindex来标识一下下一层递归从哪个元素开始递归。而且我们在这里还要明确一下去重逻辑,排序之后,相同数值大小的元素肯定是挨着的,要是当前遍历元素的前一个元素的used数组的值是false,那就代表着和当前元素num[i]的值相同的num[i-1]已经被使用过了,那么现在就不能用了,我们应该用continue结束这一次的循环,开始进行下一次的循环。
具体的代码如下
void backtrack(vector<int>&num,vector<bool>& used,int startindex)
{
res.push_back(path);
if(startindex>=num.size())return ;
for(int i=startindex,i<num.size();i++)
{
if(i>0&&num[i]==num[i-1]&&used[i-1]==false)
continue;
path.push_back(num[i]);
num[i]=false;
backtrack(num,used,i+1);
used[i]=true;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums)
{
vector<bool>used(nums.size(),false);
sort(nums.begin(),nums.end());
backtrack(num,used,0);
return res;
}