LeetCode 90.子集Ⅱ(回溯)

77 阅读1分钟

从零开始学习c++,每天起码做一道leetcode题目,在此记录,希望最后能够有所收获!

一、题目描述

90.子集Ⅱ

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入: nums = [1,2,2]
输出: [[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入: nums = [0]
输出: [[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

二、思路分析

这一题也是组合,但不同于上一题的地方在于上一题题目所给的集合中并没有重复的元素,而这一题中则有。

其实这与前面我做过的那道回溯题是一样的套路。需要设置一个used数组来记录在整个回溯过程中哪些元素出现过,哪些元素没有出现过。同时要进行一个排序。这样才能在后面的树层遍历中进行去重。

树层遍历其实就是for循环,在每一次for循环的开始,首先要检测该元素与上一个元素是否相同,如果相同的话,则需要看上一个元素是否已经出现过。如果出现过的话,这说明它们并不在同一个树层上,而是上下层的关系,那这样的枝是不能剪的。而如果未曾出现的话,则说明它们是在同一个树层上,需要剪掉。

三、AC代码

class Solution {
public:
    vector<vector<int>>ans;
    vector<int>path;
    vector<int>used=vector<int>(10,0);
    void backtracking(vector<int>& nums,int n,int startindex,vector<int> used){
        ans.push_back(path);
        if(startindex>=n){
            return;
        }
        for(int i=startindex;i<n;i++){
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            path.push_back(nums[i]);
            used[i]=1; 
            
            backtracking(nums,n,i+1,used);
            path.pop_back();
            used[i]=0;
        }
    }  
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n=nums.size();
        backtracking(nums,n,0,used);
        return ans;
    }
};

四、总结

总体并不难,但需要对如何去重心里有数。