代码随想录第二十九天

代码随想录第二十九天

    • Leetcode 491. 递增子序列
    • Leetcode 46. 全排列
    • Leetcode 47. 全排列 II

Leetcode 491. 递增子序列

题目链接: 递增子序列
自己的思路:只想到了大概,但没写出来!

正确思路:和子集的题目的区别在于是否加入到结果集中的条件和去重的方式。首先题目要求必须得数组长度大于1才可以加入到结果集中,第二去重的方式,这里选择每一层来维护一个used数组,如果之前使用过这个元素,则直接continue;回溯三部曲:1、传入参数:数组和指向数组元素的索引;2、终止条件:当数组长度超过1加入到结果集中;3、单层逻辑:先判断加入到的元素是否满足要求,path是否为空,当前元素是否小于path中最后一个元素,used数组是否已经使用过这个元素,如果都满足,才可以递归、回溯,注意回溯的时候,不要给used数组赋值0,因为是一层来维护一个used数组。

代码:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums,0);
        return res;
    }

    public void backtracking(int[] nums,int startindex){
        if (path.size()>1){
            res.add(new ArrayList(path));
        }
        //记录每一层是否重复就可以
        int[] used = new int[201];
        for (int i =startindex;i<nums.length;i++){
            if(!path.isEmpty()&&nums[i]<path.get(path.size()-1)||(used[nums[i]+100]==1)) continue;
            path.add(nums[i]);
            used[nums[i]+100]=1;
            backtracking(nums,i+1);
            path.removeLast();
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 46. 全排列

题目链接: 全排列
自己的思路:算是自己做出来的吧,至少大部分是自己写的!

正确思路:和组合问题的区别在于去除了startindex,但是加入了used数组,防止一个数组中出现重复元素,但是可以从头开始取;回溯三部曲:1、传入参数:数组和used数组;2、终止条件:当path的大小和数组大小相等,加入到结果集;3、单层逻辑:从索引0开始遍历,当used使用过这个元素,跳过这个元素,如果没有使用过,递归、回溯!

代码:

class Solution {
    Set<List<Integer>> res = new HashSet<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        //使用数组标记之前是否使用过这个元素
        used = new boolean[nums.length];
        backtracking(nums,used);
        List<List<Integer>> res1 = new ArrayList(res);
        return res1;
    }
    public void backtracking(int[] nums,boolean[] used){
        if (path.size()==nums.length){
            res.add(new ArrayList(path));
        }
        for (int i =0;i<nums.length;i++){
            if (used[i]) continue;
            path.add(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            path.removeLast();
            used[i]=false;
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 47. 全排列 II

题目链接: 全排列 II
自己的思路:其实挺简单,但没做出来!

正确思路:就是把排列和去重结合起来;回溯三部曲:1、传入参数:数组和used数组;2、终止条件:当path大小等于nums的大小时,将它加入到结果集中;3、单层逻辑:不能取之前取过的元素,当然如果当前元素等于前一个元素的话,如果上一个元素没有使用,直接去重;然后递归回溯即可!

代码:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);
        used = new boolean[nums.length];
        backtracking(nums,used);
        return res;
    }

    public void backtracking(int[] nums,boolean[] used){
        if (path.size()==nums.length){
            res.add(new ArrayList(path));
            return;
        }
        for (int i =0;i<nums.length;i++){
            //树枝和树层去重s
            if ((i>0&&nums[i]==nums[i-1]&&!used[i-1])||used[i]) continue;
            path.add(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            path.removeLast();
            used[i]=false;
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

你可能感兴趣的:(数据结构,java,开发语言,算法)