LeetCode:T90. 子集 II 回溯法去重问题

题目链接https://leetcode-cn.com/problems/subsets-ii/

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

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

示例 1:

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

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

对于第78题的子集I , 我们可以用回溯法直接来解:

    public List<List<Integer>> subsets(int[] nums) {
        backTrace(nums,0,new ArrayList<Integer>());
        return res;
    }

    List<List<Integer>> res = new ArrayList<List<Integer>>();

    public void backTrace(int[] nums , int idx, List<Integer> list_now){
        res.add(new ArrayList<Integer>(list_now));

        for(int i = idx ; i < nums.length ; i++){
            list_now.add(nums[i]);
            backTrace(nums,i+1,list_now);
            list_now.remove((Integer)nums[i]);
        }
    }

但是这一题不同的是,题目给出的数组中会有重复元素,如果继续使用子集I的方法,最终的答案里会有重复的子集,例如:
nums = [1,2,2,3]
在list_now = [ 1 ] 时 ,我们先加入nums中下标为1的元素“2”,继续往下递归可以得到结果[1,2],[1,2,2],[1,2,2,3],[1,2,3];然后回溯到 list_now = [ 1 ] 时,再次加入下标为2的元素“2” ,继续往下递归,又会得到[1,2],[1,2,3];这样结果集中就会有重复的子集;因此,我们需要想办法,在回溯过程中跳过某些重复子集;

我们画出[1,2,2,3]在回溯时的递归树:
在这里插入图片描述
标红的节点,就是多余的节点,应该要被舍弃;
可以看出被标红的节点有一个特性,就是遍历到该节点处时,新加入的元素,与其在nums中前一个位置的元素相同;因此,我们可以加入一个判断:如果当前所需要加入的元素nums[i] == nums[i-1] ,就不往下继续回溯,而是跳过该节点:

    public void backTrace(int[] nums , int idx, List<Integer> list_now){
        res.add(new ArrayList<Integer>(list_now));
        for(int i = idx ; i < nums.length ; i++){
        //如果nums[i]==nums[i-1],就跳过这一个节点;
            if(i>idx && nums[i]==nums[i-1]){continue;}
            else
                {
                list_now.add(nums[i]);
                backTrace(nums,i+1,list_now);
                list_now.remove((Integer)nums[i]);
            }
        }
    }

上面的代码中,是否跳过这一节点的判断还加了一个 i>idx ,这是因为对于每个for循环来说,backTrace(nums,i+1,list_now)等于是进入了递归树的下一层,例如上图中的这个节点:
在这里插入图片描述
对于节点[1]来说,我们需要舍弃的,不是阻止他进入递归树的下一层,而是阻止递归树的下一层中出现相同的节点;也可以这么理解:如果当前正要加入List_now的元素在这个for循环阶段没有加入过,我们才进行加入,那么第一个元素肯定是要加入的;当[1]准备加入第二个2元素时,由于2在当前for循环中加入过了,于是选择跳过;

而对于[1,2]这个节点来说,它在加入nums[2] = 2这个元素时,虽然num[2]==nums[1];但是在当前for循环中并没有加过2,于是还是需要加入,否则树在这里就直接断了。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值