Leetcode 491 递增子序列

2023-12-13 13:12:38

题意理解

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

? ?这里不止要找一个子序列,还要元素保证其在原来的集合中的前后顺序,且应为增序

? ?为保证一个增序序列,所以题目也要求子集大小最小为2.

? ?要注意:集合中的元素有重复,需要去重操作。——这就是这道题的难点。

解题思路

? ? ? ? 涉及子集问题,一般可以用回溯的方法来进行解决。

? ? ? ? 回溯的解决方案通常可以抽象为一棵树。可以画一幅画来理解:

????????紫色的部分即为需要剪枝去重的地方,所以我们需要一个设置uset来记录当前层用过的元素,当当前层有重复元素出现时,需要进行剪枝操作。

????????

1.暴力回溯+剪枝优化

?回溯算法三个常见步骤:

? ? ? ? 确定返回值和参数列表

? ? ? ? 确定终止条件:集合中所有元素遍历完,即startIndex>nums.size

? ? ? ? 确定单层逻辑:使用uset来记录当前层用过的值。

注意: 子集递增,单不是严格递增,所以允许重复值存在。

? ? ? ? ? ? 剪枝: 当前层当前树枝的重复值要剪枝。

? ? ? ? ? ? ? ? ? ? ? ? 递减子序列要剪枝。

List<List<Integer>> result=new ArrayList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums,0);
        return result;
    }
    public void backtracking(int[] nums,int startIndex){
        //结果收集
        if(path.size()>=2) result.add(new ArrayList<>(path));
        if(startIndex>=nums.length) return;//可以省略,因为startIndex>=nums.length,下面循环不会进入
        //记录当前树枝当前层用过的值
        Set<Integer> uset=new HashSet<>();
        for(int i=startIndex;i<nums.length;i++){
            if(uset.contains(nums[i])){//当前树枝当前层树枝重复则剪枝
                continue;
            }
            if(path.size()!=0&&nums[i]< path.getLast()) continue;//递减时剪枝
            uset.add(nums[i]);
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.removeLast();
        }
    }

2.分析

时间复杂度:O(n\times 2^{n})

空间复杂度:O(n)

文章来源:https://blog.csdn.net/lt_BeiMo/article/details/134966005
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。