【代码随想录day 24】 力扣 90. 集合II
视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J/?vd_source=a935eaede74a204ec74fd041b917810c
文档讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html#%E6%80%9D%E8%B7%AF
力扣题目:https://leetcode.cn/problems/subsets-ii/
其实这道题时78.集合和40.组合总和III的结合体,主要需要注意以下几点:
- 首先需要将数组排序,方便我们后续操作
- 子集去重:为了防止找到前面的元素从而输出相同的子集,在遍历过程中应该像78.集合中一样,不要向前遍历,要向后遍历,好马不吃回头草。
- 数层去重:为了防止数组中重复元素导致的重复子集,我们引入used,used表示每一个数是否使用过的情况,如果相同元素都使用过,说明这个是在同一树枝上的集合,说明这个子集合法,如果发现相同元素时used显示一个用过一个没用过,说明重新开始遍历到了重复元素,所以直接continue掉他
- 在bool数组的赋值中,可以直接vector used(nums.size(), false);赋值,用for循环力扣会超时报错。
class Solution {
private:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums, int startIndex, vector<bool>& used){//向result数组中存入子集result.push_back(path);/*//判断终止条件if(startIndex >= nums.size()){return;}*///单层搜索for(int i = startIndex; i < nums.size(); i++){//树层去重if(i > 0 && nums[i] == nums[i-1] && used[i-1] == false)//如果i>0且nums的i和i-1相等并且没有用过之前的重复元素,说明时新的遍历下的重复元素,剪枝删掉{continue;}//存入元素path.push_back(nums[i]);//更新usedused[i] = true;//回溯算法backtracking(nums, i + 1, used);//弹出元素path.pop_back();//更新usedused[i] = false;}return;}
public:vector<vector<int>> subsetsWithDup(vector<int>& nums) {//path和result初始化path.clear();result.clear();//used初始化并赋初值vector<bool> used(nums.size(), false);sort(nums.begin(), nums.end()); // 去重需要排序//执行回溯算法backtracking(nums, 0, used);//返回结果return result;}
};