【回溯法】递增子序列问题 Java

CSDN话题挑战赛第2期
参赛话题:算法题解

1.题目描述

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例:

在这里插入图片描述

2.题目链接

来源:https://leetcode.cn/problems/increasing-subsequences

3.思路讲解

  1. 回溯法参数:startIndex —— 起始位置, list —— 存储路径的数组
  2. 结束条件:list 的长度等于大于 2,且满足递增,即可加入结果中
  3. 单层逻辑:判断当前层是否出现与当前节点重复的数字,未出现,加入当前节点

难点: 本题与组合问题非常像,都是很明显可以看出是使用回溯法的问题,但是本题我们不能再通过排序去重了,因为本题的结果是需要有顺序的,因此难点在于我们如何进行结果去重。

首先,我们来分析一下,产生重复答案的情况为:在同层节点(同一父节点的子节点)中,已经使用过的某一数字又出现了,以下图为例,当前层已经选择过 7 这个元素时,若是再选择 7,前面已经添加过一遍的 {4,7},又会再被添加一遍,因此对这种情况要进行剪枝。

去重具体操作方法:

通过 HashSet 记录当层已经使用过的节点,若判断已经 HashSet 中已经存在该元素,则剪枝

在这里插入图片描述

4.代码

class Solution {
    //存放结果
    List<List<Integer>> result = new ArrayList<>();
    //暂存结果
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> findSubsequences(int[] nums) {
        backTrack(nums, 0);
        return result;
    }

    private void backTrack(int[] nums, int startIndex) {
        if(path.size() > 1){
            result.add(new ArrayList<>(path));//注意这⾥不要加return,因为要取树上的所有节点
        }
        HashSet<Integer> uset = new HashSet<>();//录本层元素是否重复使⽤,新的⼀层uset都会重新定义(清空)
        for (int i = startIndex; i < nums.length; i++) {
            //!path.isEmpty()&&nums[i]<path.get(path.size()-1)) : 保证子序列是递增的
            //!uset.add(nums[i]) :保证在同一层不会重复使用相同数字
            if ((!path.isEmpty()&&nums[i]<path.get(path.size()-1))||!uset.add(nums[i])) {
                continue;
            }
            path.add(nums[i]);
            backTrack(nums, i + 1);
            path.remove(path.size() - 1);
        }
    }
}

5.感想

只是一味的去被回溯法模板不是一劳永逸的,学会画回溯树,自己分析回溯法执行过程,剪枝过程,通过思考不断提升我们对题目的理解能力,一起加油吧,大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值