[豪の算法奇妙冒险] 代码随想录算法训练营第二十五天 | 491-递增子序列、46-全排列、47-全排列Ⅱ

代码随想录算法训练营第二十五天 | 491-递增子序列、46-全排列、47-全排列Ⅱ


LeetCode491 递增子序列

题目链接:https://leetcode.cn/problems/non-decreasing-subsequences/description/

文章讲解:https://programmercarl.com/0491.递增子序列.html

视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置

​ 同一父节点下的同层上使用过的元素就不能再使用了,所以要进行树层去重。这里使用HashSet实现树层去重,add后不用再remove,因为它是记录本层元素是否重复使用,新的一层的HashSet都会重新定义(清空),它只负责本层

image-20260110205041922

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> records = new ArrayList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0, -100);
        return result;
    }

    public void backTracking(int[] nums, int start, int tailNum){
        if(records.size() >= 2){
            result.add(new ArrayList<>(records));
        }
        HashSet<Integer> used = new HashSet<>();
        for(int i = start; i < nums.length; i++){
            if((!records.isEmpty() && records.get(records.size()-1) > nums[i]) || used.contains(nums[i])){
                continue;
            }
            records.add(nums[i]);
            used.add(nums[i]);
            backTracking(nums, i+1, nums[i]);
            records.remove(records.size()-1);
        }
    }
}

LeetCode46 全排列

题目链接:https://leetcode.cn/problems/permutations/description/

文章讲解:https://programmercarl.com/0046.全排列.html

视频讲解:https://www.bilibili.com/video/BV19v4y1S79W/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 首先,排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前的子集问题以及组合问题不同。可以看出,元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题时就不用使用startIndex了

​ 一个排列里一个元素只能使用一次,所以还需要使用一个used数组,用来标记已经选择的元素,防止重复选择

image-20260110210213117

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> records = new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
        boolean[] used = new boolean[nums.length];
        backTracking(nums, used);
        return result;
    }

    public void backTracking(int[] nums, boolean[] used){
        if(records.size() == nums.length){
            result.add(new ArrayList<>(records));
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(used[i]){
                continue;
            }
            records.add(nums[i]);
            used[i] = true;
            backTracking(nums, used);
            used[i] = false;
            records.remove(records.size()-1);
        }
    }
}

LeetCode47 全排列Ⅱ

题目链接:https://leetcode.cn/problems/permutations-ii/description/

文章讲解:https://programmercarl.com/0047.全排列II.html

视频讲解:https://www.bilibili.com/video/BV1R84y1i7Tm/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 这道题目和 LeetCode46 全排列 的区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列,意味着需要树层去重

​ 同一父节点下的同层上使用过的元素就不能再使用了,所以要进行树层去重。这里使用HashSet实现树层去重,add后不用再remove,因为它是记录本层元素是否重复使用,新的一层的HashSet都会重新定义(清空),它只负责本层

image-20260110211302915

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> records = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        backTracking(nums, used);
        return result;
    }

    public void backTracking(int[] nums, boolean[] used){
        if(records.size() == nums.length){
            result.add(new ArrayList<>(records));
            return;
        }
        HashSet<Integer> hash = new HashSet<>();
        for(int i = 0; i < nums.length; i++){
            if(used[i] || hash.contains(nums[i])){
                continue;
            }
            records.add(nums[i]);
            used[i] = true;
            hash.add(nums[i]);
            backTracking(nums, used);
            used[i] = false;
            records.remove(records.size()-1);
        }
    }
}
posted @ 2026-01-10 21:18  SchwarzShu  阅读(1)  评论(0)    收藏  举报