题目:
思路:
思路很直观,递归遍历所有可能的情况。关键是如何去除重复组合。
首先sort一下,把相同的元素都放在一起。去重的关键是判断前一个元素是否相等并且是否已被选中。如果num[i-1]等于nums[i]并且nums[i-1]已经被选中,那么nums[i]是可以的;否则,nums[i]不可以被选择。
上图中,nums[i-1]已经被选中,所以nums[i]是可以被选择的。这样会产生一种连锁反应,如果第一个2被选中,后面所有的2都会逐个被选中;反之,如果第一个2没被选中,那么后面所有2都不会被选中。这样就不会出现“破碎”的情况(就是有的2被选中,有的2没被选中的情况),以此来避免重复组合。
代码实现:
class Solution {
public:
void f(vector<int>& nums, vector<bool> &isSelected, vector<int> &tmp, int begin, vector<vector<int>> &ans){
for (int i = begin; i < nums.size(); ++i){
if (i > 0 && nums[i-1] == nums[i] && isSelected[i-1] == false){
continue;
}
tmp.push_back(nums[i]);
isSelected[i] = true;
ans.push_back(tmp);
f(nums, isSelected, tmp, i+1, ans);
isSelected[i] = false;
tmp.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<int> tmp;
vector<bool> isSelected(nums.size(), false);
vector<vector<int>> ans;
ans.push_back(tmp);
sort(nums.begin(), nums.end());
f(nums, isSelected, tmp, 0, ans);
return ans;
}
};
discuss:
递归回溯
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
vector<int> vec;
subsetsWithDup(res, nums, vec, 0);
return res;
}
void subsetsWithDup(vector<vector<int>> &res, vector<int> &nums, vector<int> &vec, int begin){
res.push_back(vec);
for (int i = begin; i != nums.size(); ++i){
if (i == begin || nums[i] != nums[i-1]){
vec.push_back(nums[i]);
subsetsWithDup(res, nums, vec, i + 1);
vec.pop_back();
}
}
}
};