回溯算法:递增子序列

491. 递增子序列

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

输入:[4, 6, 7, 7]
输出:[[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

思路

90. 子集 II 是通过排序,再加一个标记数组来达到去重的目的。而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。

回溯三部曲

1.递归函数参数

    List<Integer> temp = new ArrayList<Integer>();
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    private void backtracking(int[] nums, int startIndex) {}

2.终止条件

  • 可以不加终止条件,startIndex每次都会加1,并不会无限递归
  • 题目要求递增子序列大小至少为2

3.单层搜索逻辑

  • 本题只要同层重复使用元素,递增子序列就会重复
  • 如果选取的元素小于子序列最后一个元素,那么就不是递增的,需要去掉

去重的逻辑代码:

            if ((!temp.isEmpty() && nums[i] < temp.get(temp.size()-1))
                    || uset.contains(nums[i])) {
                continue;
            }

代码

class Solution {
    List<Integer> temp = new ArrayList<Integer>();
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums,0);
        return ans;
    }
    private void backtracking(int[] nums, int startIndex) {
        if(temp.size() >=2) {
            ans.add(new ArrayList<>(temp)); // 收集子集
            // 注意这里不要加return,因为要取树上的所有节点
        }
        HashSet<Integer> uset = new HashSet<>(); // 使用set对本层元素进行去重
        for (int i = startIndex; i < nums.length; i++) {
            if ((!temp.isEmpty() && nums[i] < temp.get(temp.size()-1))
                    || uset.contains(nums[i])) {
                continue;
            }
            uset.add(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了
            temp.add(nums[i]);
            backtracking(nums, i + 1);
            temp.remove(temp.size()-1);
        }
    }
}
posted @ 2021-05-21 11:56  当康  阅读(125)  评论(0编辑  收藏  举报