LeetCode_Array_90. Subsets II子集 II(C++)【递归+剪枝】

目录

1,题目描述

英文描述

中文描述

2,解题思路

3,AC代码

4,解题过程


1,题目描述

英文描述

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: [1,2,2]
Output:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

中文描述

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

说明:解集不能包含重复的子集。

示例:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2,解题思路

参考@misaka【C++ 双100%思路】

  • 假设数组中无重复元素,比如nums=[1,2,3,4],递归过程如下:

  • 从根节点(这里指第二层中的节点,顶端的空节点是为了将各个树连接起来)到任意节点形成的路径,即为输出结果的一部分。比如根节点为1时,[1]、[1,2]、[1,2,3]、[1,2,3,4]、[1,2,4]、[1,3]、[1,3,4]、[1,4]均为结果集中的一部分;
  • 假设数组中有重复元素时,比如nums=[1,2,2,4],不加剪枝的递归过程如下:

  •  可以看出绿色部分是递归过程中的重复部分,仍以根节点1为例,[1]、[1,2]、[1,2,2]、[1,2,2,4]、[1,2,4]、[1,2]、[1,2,4]、[1,4];
  • 出现重复的原因是,相邻两个元素相同,故可以想到,遍历到相同元素时将其跳过(剪枝),从而避免重复;

  •  关键代码如下:
        for(int i=depth; i<v.size(); ++i) {
            if(i > depth && v[i] == v[i-1]) continue;   // 剪枝
            cur.push_back(v[i]);        // 入栈
            dfs(i+1);                   // 深度加一
            cur.pop_back();             // 出栈(配对出现)
        }

 

3,AC代码

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> cur;                    // 当前子集元素
    vector<int> v;                      // 全局变量 对原数组进行拷贝 从而不需借助参数传递
    void dfs(int depth) {
        ans.push_back(cur);
        if(depth == v.size())  return;  // 递归出口
        for(int i=depth; i<v.size(); ++i) {
            if(i > depth && v[i] == v[i-1]) continue;   // 剪枝
            cur.push_back(v[i]);        // 入栈
            dfs(i+1);                   // 深度加一
            cur.pop_back();             // 出栈(配对出现)
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end()); // 排序 便于剪枝
        v = nums;
        dfs(0);
        return ans;
    }
};

 

4,解题过程

因为不允许有重复的子集,一开始就想到用set处理,其余按照正常递归来写,直接超时。现在想想确实很憨(lll¬ω¬)

看了大神的代码,豁然开朗,对原数组进行排序,重复的元素必定排列在一起,所以递归时跳过即可避免重复;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值