代码随想录算法训练营第二十九天 | 491.递增子序列 46.全排列 47.全排列 II

代码随想录算法训练营第二十九天 | 491.递增子序列 46.全排列 47.全排列 II

一、力扣491.递增子序列

题目链接
思路:从数组中取递增子序列,不能排序,纵向递归要一直数组结束,所以不需要提前return,而且list的size只要大于2就可以收集到总集合中,纵向是不需要去重的,比如577,可以都要了。横向的话,是需要去重的,重复的数字是不可以用的,比如577,先取5,会拿到57,577,然后递归返回到第二层,会取第二个7变成57,所以横向要去重,可以在每次进入for之前设置一个hashset,遇到值就设置进去,如果当前值包含就要去重,想下递归每一次都是一个新集合,而横向遍历却会记录都加过哪些值以便去重。

class Solution {
    List<List<Integer>> arrayLists = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0);
        return arrayLists;
    }
    void backTracking(int[] nums, int startIndex) {
        if (list.size() > 1) {
            arrayLists.add(new ArrayList<>(list));
        }
        HashSet<Integer> set = new HashSet<>();
        for (int i = startIndex; i < nums.length; i++) {
            if (!list.isEmpty() && list.get(list.size() - 1) > nums[i] || set.contains(nums[i])) {
                continue;
            }
            list.add(nums[i]);
            set.add(nums[i]);
            backTracking(nums, i + 1);
            list.remove(list.size() - 1);
        }
    }
}

二、力扣46.全排列

题目链接
思路:终止条件list大小等于nums大小就满了可以终止。没有重复的不用去重,排列问题每次for都要从0开始所以也不要startIndex,纵向递归只需要不把已经添加的数加进去即可。

class Solution {
    List<List<Integer>> arrayLists = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        used = new boolean[nums.length];
        backTracking(nums);
        return arrayLists;
    }
    void backTracking(int[] nums) {
        if (list.size() == nums.length) {
            arrayLists.add(new ArrayList<>(list));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i]) continue;
            list.add(nums[i]);
            used[i] = true;
            backTracking(nums);
            list.remove(list.size() - 1);
            used[i] = false;
        }
    }
}

三、力扣47.全排列 II

题目链接
思路:上面那倒题目因为是不重复的,所以不用考虑横向,只用考虑纵向就行,用过的不要再加了,而这道题目,有重复值,所以纵向要考虑,横向也要考虑,横向的话如果前一个值和当前值相等并且没用过(回溯了)就要去重,纵向依然是当前值没用过才加入,用过的就要去重。

class Solution {
    List<List<Integer>> arrayLists = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    boolean[] used;
    public List<List<Integer>> permuteUnique(int[] nums) {
        used = new boolean[nums.length];
        Arrays.sort(nums);
        Arrays.fill(used, false);
        backTracking(nums);
        return arrayLists;
    }
    void backTracking(int[] nums) {
        if (list.size() == nums.length) {
            arrayLists.add(new ArrayList<>(list));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (i > 0 && nums[i - 1] == nums[i] && !used[i-1]) continue;
            if (!used[i]) {
                list.add(nums[i]);
                used[i] = true;
                backTracking(nums);
                list.remove(list.size() - 1);
                used[i] = false;
            }
        }
    }
}

你可能感兴趣的:(算法)