给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
解题思路:
我们看到第 4 行黑色的部分,重复了,是怎么造成的呢?
第 4 行新添加的 2 要加到第 3 行的所有解中,而第 3 行的一部分解是旧解,一部分是新解。可以看到,我们黑色部分是由第 3 行的旧解产生的,橙色部分是由新解产生的。
而第 1 行到第 2 行,已经在旧解中加入了 2 产生了第 2 行的橙色部分,所以这里如果再在旧解中加 2 产生黑色部分就造成了重复。
所以当有重复数字的时候,我们只考虑上一步的新解,算法中用一个指针保存每一步的新解开始的位置即可。
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> res = {{}};
if(nums.empty())
return res;
sort(nums.begin(), nums.end()); // 排序
int start = 0;
for (int i = 0; i < nums.size(); ++i) {
int len = res.size();
if (i>0 && nums[i]!=nums[i-1])
start = 0; // 新数字,全部遍历
for(int j = start; j < len; ++j){//如果出现重复元素,则start的值为上次新解的位置
//对res中的每个数组添加新元素
vector<int> tmp = res[j];
tmp.push_back(nums[i]);
res.push_back(tmp);
}
//len-start的值为上一步新解的数量,在重复的情况下,当前步的新解数量与上一步的新解数量保持一致
//所以start的起始值为res.size()-新解数量
start = res.size() - (len - start); // 重复数字,从上一轮新添加的部分开始
}
return res;
}
};