1.题目链接:
2.解题思路:
2.1.题目要求:
给一个可能有重复元素的数组 nums ,要求返回其所有可能的子集,但子集不能重复。
比如:
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
2.2.思路:
数组里有重复,但要求返回的子集不能有重复,用N叉树的思路来做,for+递归,用used去除树层
上的选择重复,保留树枝上的选择重复。终止条件是遇见叶子节点返回。
2.3.回溯三部曲:
2.3.1.确定回溯函数参数
path储存,result结果集,start确认下一次开启次数,used去重
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex, vector<bool>& used) {
2.3.2.确定终止条件
遇见叶子节点
if(startIndex >= nums.size()) {
return;
}
2.3.3.确定单层遍历逻辑
先排序(在2.3.4.总代码那),去2.2思路看图。
used去重,i > 0 的时候在开启判断,递归一层,本层used[ i ]上为1,回溯返回成 0 ,这样递归(树枝)的时候遇见 nums[i] == nums[i - 1] 的情况,其used[ i - 1]就会为 1 ,代表树枝遍历遇见重复的值,可以选,
树层的时候,因为回溯上来了,其used[ i - 1]就会为 0 ,通过used的情况判断就好了。
result.push_back(path);
//输入结果集的代码在终止条件上面,否则最后一个元素会在输入结果集之前,就已经被终止条件返回
for (int i = startIndex; i < nums.size(); i++) {
// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
// 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();
}
}
2.4.总代码:
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
result.push_back(path);
if(startIndex >= nums.size()){
return;
}
for (int i = startIndex; i < nums.size(); i++) {
// 而我们要对同一树层使用过的元素进行跳过
if (i > startIndex && nums[i] == nums[i - 1] ) { // 注意这里使用i > startIndex
continue;
}
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
result.clear();
path.clear();
sort(nums.begin(), nums.end()); // 去重需要排序
backtracking(nums, 0);
return result;
}
};
3.遇见的问题:
无
4.记录:
类似的