题目(leecode T90):
给你一个整数数组 nums
,其中可能包含重复元素,请你返回该数组所有可能的
子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
方法:本题和昨天的子集问题的唯一区别就是本题要求输出的结果中不能有重复,因此需要我们在子集问题的基础上加上一个去重的操作,去重的方法在之前组合的一道题目中也有用过,就是用used数组来表示当前集合中有哪些元素用过与没用过的。和之前的使用方法是一致的,如果nums[i] = nums[i-1] && used[i - 1] == false就说明nums[i]和nums[i-1]是相同的并且nums[i - 1]已经使用过了,因此nums[i]就不用再计算了,否则就会发生同一树层上的元素的重复从而导致结果集中有重复,因此在遇到这种情况就直接跳过即可。
1:传入参数与返回值:传入nums数组,控制下一个操作数位置的startIndex和判断使用与否的数组used
2:终止条件:和昨天一样,因为我们是要收集所有可能的叶子节点,因此我们可以省略终止条件,因为这个条件在for循环中其实已经存在了
3:单层处理逻辑:和子集问题一样就是最基础的递归加回溯方式,本题的重点在于去重,即多加了一个used数组的判断条件。
题解:
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex, vector<bool>& used) {
result.push_back(path);
for (int i = startIndex; i < nums.size(); i++) {
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过需要跳过
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
path.push_back(nums[i]);
used[i] = true;
backtracking(nums, i + 1, used);
used[i] = false;
path.pop_back();
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
result.clear();
path.clear();
vector<bool> used(nums.size(), false);
sort(nums.begin(), nums.end());
backtracking(nums, 0, used);
return result;
}
};