算法day29 | 回溯:递增子序列(不排序去重)、全排列、全排列Ⅱ(去重)

1. 自增子序列

1.1 链接

https://leetcode.cn/problems/non-decreasing-subsequences/

1.2 关键知识点

-//本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。所以不能使用之前的去重逻辑!

1.3 自己遇到的细节问题

  • LinkedList长度是size
  • map.getOrDefault(nums[i], 0)获取值的使用

1.4 题解

class Solution {
    //根本还是求子集
    //本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。所以不能使用之前的去重逻辑!
    List<List<Integer>> rs = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0);
        return rs;
    }

    public void backTracking(int[] nums, int startIdx){
        if(path.size() >= 2){
            rs.add(new ArrayList<>(path));
        }
        //每一层判断
        HashMap<Integer, Integer> map = new HashMap<>();
        for(int i = startIdx; i < nums.length; i ++){
            //父子的判断逻辑 以及层间的
            if((!path.isEmpty() && path.getLast() > nums[i]) || map.getOrDefault(nums[i], 0) > 0){
                continue;
            }else{
                map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
                path.add(nums[i]);

                backTracking(nums, i + 1);
                path.removeLast();
            }

        }
    }
}

2.全排列

为什么排列问题不用 startIndex?可以理解成一个单向一个双向。startindex的存在就是构造一个单向。

2.1 链接

https://leetcode.cn/problems/permutations/

2.2 关键知识点

  • 不重复选取数字的设置:由于排列问题和组合问题不同,不需要startindex来每次获取序列的后部分(换句话说是通过i+1实现的),而是i=0,开始,因此需要一个used数组来判断是否挑选到了上层数字;

2.3 自己遇到的细节问题

  • 注意用path比
    -注意一定要转为正确的ArrayList,不然传进去是空

2.4 题解

class Solution {
    List<List<Integer>> rs = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;//默认值为false
    public List<List<Integer>> permute(int[] nums) {
        used = new boolean[nums.length];//used初始化
        backTracking(nums);
        return rs;
    }
    public void backTracking(int[] nums){
        if(nums.length == path.size()){//注意用path比
            rs.add(new ArrayList<>(path));//注意一定要转为正确的ArrayList,不然传进去是空
        }

        for(int i = 0; i < nums.length; i ++){
            if(!used[i]){//为了跳过当前数字
                used[i] = true;
                path.add(nums[i]);
                backTracking(nums);
                used[i] = false;
                path.removeLast();
            }//这样写没有continue也行
        }
        
    }
}

3.全排列Ⅱ

3.1 链接

https://leetcode.cn/problems/permutations-ii/

3.2 关键知识点

如果排列问题去重(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false),和组合问题去重相比

  • 类似但不同:树层的进入大于1:不再通过startindex判断一个树层的进入,而是i>0就代表树层的进入;
  • 不同:树层已经被使用(组合问题中没有的条件,因为每次输入的i+1就跳过了用过的):并且跳过使用过的同一树层(因为可能正在作为上树层被跳过,而在本树层虽然与前一个相同但未被使用)
  • 相同:需要排序,类似于组合问题的相等判断

3.3 自己遇到的细节问题

  • 树层去重和树枝去重的理解
  • 又忘记排序了。。

3.4 题解

class Solution {
    List<List<Integer>> rs = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> permuteUnique(int[] nums) {
        used = new boolean[nums.length];
        Arrays.sort(nums);//一定要记得排序。。
        backTracking(nums);
        return rs;
    }
    public void backTracking(int[] nums){
        if(path.size() == nums.length){
            rs.add(new ArrayList<>(path));
            return;
        }

        for(int i = 0; i < nums.length; i ++){
            if(i > 0 && used[i - 1] == false && nums[i] == nums[i - 1]){//树层没用+连续相等(基于排序)
                continue;//去重
            }else{
                if(!used[i]){
                    used[i] = true;
                    path.add(nums[i]);
                    backTracking(nums);
                    used[i] = false;
                    path.removeLast();
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值