算法思路
在LeetCode 78. 子集 中我们知道求子集问题与求全排列问题 的区别在于我们不需要考虑每个数在的位置或每个位置上是什么数,我们只在乎每一个数选或不选。因此对于有重复元素的子集问题,我们的思路不再像全排列那样关心每个数的先后关系,我们只需要关心相同的数选几个。具体步骤如下:
- 将原数组排序,目的是将相同元素放在一起,之后好计算每个相同数的个数
- 计算出当前数相同的个数,然后分别做出不选,选1个,选2个…的选择,然后递归到下一层
- 注意在每做完一个选择递归到下一层时不需要马上回溯,因为我们选1个,选2个…每一个之后的选择是建立在之前选择上多选一个,所以我们不需要马上回溯
- 当做出所有选择后,我们才需要将选择的这一段相同的数清空,所以回溯需要在做完所有选择后再进行
C ++代码
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
dfs(nums, 0);
return res;
}
void dfs(vector<int>& nums, int u)
{
int n = nums.size();
if(u == n)
{
res.push_back(path);
return;
}
int k = u;
while(k < nums.size() && nums[k] == nums[u]) k++;
dfs(nums, k); //当前这种数一个都不选
for(int i = u; i < k; i++) //分别选1个,2个...
{
path.push_back(nums[u]);
dfs(nums, k);
}
path.erase(path.end() - (k - u), path.end()); //回溯,将选择的这一段相同的数全部清空
}
};