Subsets II - LeetCode

时间:2024-01-05 11:40:26

题目链接

Subsets II - LeetCode

注意点

  • 有重复的数字
  • 数组可能是无序的,要先排序

解法

解法一:递归,只需要在Subsets中递归写法的基础上多加一句if(find(ret.begin(),ret.end(),tmp) == ret.end()) ret.push_back(tmp);j即可,因为已经排序了,所以加进去的如果已经存在就说明是重复的。

class Solution {
public:
typedef vector<int> v;
void recursion(int start,v nums,v tmp, vector<v>& ret)
{
if(find(ret.begin(),ret.end(),tmp) == ret.end()) ret.push_back(tmp);
int n = nums.size();
for(int i = start;i < n;i++)
{
tmp.push_back(nums[i]);
recursion(i+1,nums,tmp,ret);
tmp.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ret;
v tmp;
recursion(0,nums,tmp,ret);
return ret;
}
};

Subsets II - LeetCode

解法二:递归。只需要在Subsets中递归写法的基础上多加一句while(i+1 < n && nums[i] == nums[i+1]) i++;即可,这句话的作用就是把下图中树结点为X的剪枝。

                        []
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 2] [1 2] X [1] [2 2] [2] X []
class Solution {
public:
typedef vector<int> v;
void recursion(int start,v nums,v tmp, vector<v>& ret)
{
ret.push_back(tmp);
int n = nums.size();
for(int i = start;i < n;i++)
{
tmp.push_back(nums[i]);
recursion(i+1,nums,tmp,ret);
tmp.pop_back();
while(i+1 < n && nums[i] == nums[i+1]) i++;
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ret;
v tmp;
recursion(0,nums,tmp,ret);
return ret;
}
};

Subsets II - LeetCode

解法三:非递归。在Subsets中非递归写法的基础上进行修改,如果当前数字和上一次循环的数字一样,那么就只能在上一次循环产生的集合后面追加当前数字,而不能在所有集合后面追加

class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
if(nums.empty()) return {};
sort(nums.begin(),nums.end());
vector<vector<int>> ret(1);
int i,j,n = nums.size(),last = nums[0],lastSize = 1;
for(i = 0;i < n;i++)
{
if(last != nums[i])
{
last = nums[i];
lastSize = ret.size();
}
int m = ret.size();
for(j = m-lastSize;j < m;j++)
{
ret.push_back(ret[j]);
ret.back().push_back(nums[i]);
}
}
return ret;
}
};

Subsets II - LeetCode

小结