90. 子集 II
基本是看这位大佬的题解,用C++实现了一遍
1.回溯法
这个比较好改,我们只需要判断当前数字和上一个数字是否相同,相同的话跳过即可。当然,要把数字首先进行排序。
class Solution {
public:
vector> subsetsWithDup(vector &nums) {
vector> res;
vector item;
sort(nums.begin(), nums.end());
helper(res, item, nums, 0);
return res;
}
void helper(vector> &res, vector item, vector &nums,
int level) {
res.push_back(item);
for (int i = level; i < nums.size(); i++) {
if (i > level && nums[i] == nums[i - 1])
continue;
item.push_back(nums[i]);
helper(res, item, nums, i + 1);
item.pop_back();
}
}
};
int main() {
Solution s;
vector nums = {1, 2, 2, 2, 3};
vector> res;
res = s.subsetsWithDup(nums);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < res[i].size(); j++) {
cout << res[i][j] << " ";
}
cout << endl;
}
cout << endl << res.size();
return 0;
}
2.迭代法
我们发现出现了重复的数组,那么我们可不可以像解法一那样,遇到重复的就跳过这个数字呢?答案是否定的,如果最后一步 [ 1 2 2 ] 增加了 2 ,跳过后,最终答案会缺少 [ 2 2 ]、[ 1 2 2 ] 这两个解。我们仔细观察这两个解是怎么产生的。
我们看到第 4 行黑色的部分,重复了,是怎么造成的呢?
第 4 行新添加的 2 要加到第 3 行的所有解中,而第 3 行的一部分解是旧解,一部分是新解。可以看到,我们黑色部分是由第 3 行的旧解产生的,橙色部分是由新解产生的。
而第 1 行到第 2 行,已经在旧解中加入了 2 产生了第 2 行的橙色部分,所以这里如果再在旧解中加 2 产生黑色部分就造成了重复。
所以当有重复数字的时候,我们只考虑上一步的新解,算法中用一个指针保存每一步的新解开始的位置即可。
class Solution {
public:
vector> subsetsWithDup(vector &nums) {
vector> res(1);
sort(nums.begin(), nums.end());
int start = 1;
for (int i = 0; i < nums.size(); i++) {
int len = res.size();
for (int j = 0; j < len; j++) {
if (i > 0 && nums[i] == nums[i - 1] && j < start)
continue;
vector tmp = res[j];
tmp.push_back(nums[i]);
res.push_back(tmp);
}
start = len;
}
return res;
}
};