代码注释(递归枚举+剪枝) 491.递归子序列


491.递归子序列

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

来源:LeetCode
网站:https://leetcode-cn.com/problems/increasing-subsequences/

版本一:递归枚举+Set去重

    /**
     * 算法一:递归枚举
     * 思路:每一个位置的数,选择或不选择
     */
    Set<List<Integer>> set = new HashSet<>();;
    public List<List<Integer>> findSubsequences(int[] nums) {
        if(nums == null || nums.length == 0) return new ArrayList<>();

        dfs(nums,0,new ArrayList<>());//递归枚举

        List<List<Integer>> ans = new ArrayList<>();//将set中的list取出来
        for(List<Integer> ls : set){
            ans.add(ls);
        }

        return ans;
    }


    private void dfs(int[] nums, int index, List<Integer> list){
        if(index >= nums.length){
            if (list.size() > 1)
                set.add(new ArrayList(list));
            return;
        }

        //选择当前数
        if(list.size() == 0 || list.get(list.size()-1) <= nums[index]){//选择的第一个数 或者 cur >= pre
            list.add(nums[index]);
            dfs(nums,index+1,list);
            list.remove(list.size()-1);
        }

        //不选择当前数
        dfs(nums, index + 1, list);
    }

算法一可以改进的地方:
1、list.get(list.size()-1) <= nums[index],所以每次都需要先判断list.size()是否大于0
2、虽然实现了部分剪枝,但是仍然不能达到去重的效果,所以需要Set来筛选,效率不高。

版本二:递归枚举+剪枝

    /**
     * 算法二:递归枚举+剪枝
     */
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public List<List<Integer>> findSubsequences2(int[] nums) {
        if(nums == null || nums.length == 0) return new ArrayList<>();

        dfs2(nums,0,Integer.MIN_VALUE);

        return ans;
    }

    /**
     * 1.前一个选择的数和当前数不同
     *  ① 如果当前数大于或等于前一个选择的数,选择当前数
     *  ② 不选择当前数
     * 2.前一个选择的数和当前数相同
     *  ① 选择当前数
     *  ② 不选择当前数(可以省略,因为,前一个选择后一个不选择的结果与前一个不选择后一个选择的情况相同)
     *      所以,这个问题中出现重复解的原因就是 2.②
     */
    private void dfs2(int[] nums, int index,int lastVal){
        if(index >= nums.length){
            if (tmp.size() > 1)
                ans.add(new ArrayList<>(tmp));
            return;
        }

        //选择当前数
        if (nums[index] >= lastVal){//剪枝,当前数需要比前一个选择的数大或等于
            tmp.add(nums[index]);
            dfs2(nums,index+1,nums[index]);
            tmp.remove(tmp.size()-1);//回溯
        }
        //不选择当前数
        if (lastVal != nums[index])//去重,如果前一个选择的数和当前的数相同,可以不用考虑这次不选择的情况
            dfs2(nums,index+1,lastVal);
    }

读者如果仍然无法理解 if (lastVal != nums[index]),建议可以自己尝试着画一画递归树。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值