代码随想录算法训练营day29|递增子序列、全排列、全排列Ⅱ

2023.4.12 递增子序列

491. 递增子序列 - 力扣(LeetCode)

这道题既不是所有节点,也不是所有叶子结点,如何确定终止条件?

其实还是全部节点,我们只需要对加入结果集的元素进行筛选就行了

题目给出序列并不是一个递增的序列,只是给的例子是递增的,这需要我们在实际中去判断它是否是递增的。

此外,关于去重处理,由于本题是不能对其进行排序处理的,所以我们需要使用哈希表来进行去重的操作

几个关键点:

1.实际上本题还是遍历的所有节点,并不只是叶子结点,因此不需要return处理,但是我们的节点也是有要求的,必须长度大于等于2,这一点可以使用条件判断来处理加入结果集的数据。

2.题目给出的序列例子是递增的,但是实际并没有说明全部算例是递增的,所以还需要我们对加入结果的数据进行递增的判断

3.此题可能会出现重复的元素,但是它并不能排序,显然不能靠之前我们的排序去重方法,这里只能依靠哈希表来进行去重

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 start){
        //只有当path的长度大于2我们才将其放入结果集
        if(path.size() >=2){
            res.add(new ArrayList(path));
            //因为是处理整个节点,我们不能设置return;
        }
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for(int i = start;i<nums.length;i++){
            //当前元素如果小于前一个元素,不能构成一个递增的子序列,因此需要继续循环,此外,在判断时,我们的path不能为空,否则会出现空指针异常
            if(!path.isEmpty() && nums[i] < path.getLast()){
                continue;
            }
            //如果当前数字在同一层被使用过,也不能继续使用
            //每次进入backTracking,我们的hashMap就会重置,只有在同一层的for循环中,才会出现重复的情况。
            if(hashMap.getOrDefault(nums[i],0) >= 1){
                continue;
            }
            //正常处理逻辑
            hashMap.put(nums[i],hashMap.getOrDefault(nums[i],0) + 1);
            path.add(nums[i]);
            backTracking(nums,i+1);
            //回溯
            path.removeLast();
        }
    }
}

2023.4.12 全排列

46. 全排列 - 力扣(LeetCode)

我们之前做过的都是组合问题,也就是对结果集的顺序是没有要求的,而排列则对我们的顺序有要求,也就是说,即使是相同的元素,位置不同也当做不同结果。

因此,对于我们的排列,我们已经不再需要设置初始下标start了,直接传入初始下标即可,但是需要注意,我们已经选择的元素不再需要重复选取,因此需要使用一个boolean数组来标记那些元素已经被选择了。

此外,这道全排列也是要求我们求叶子结点上的数据,因此终止条件需要加return

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
    used = new boolean[nums.length];
    backTracking(nums);
    return res;
    }
    public void backTracking(int[] nums){
    if(path.size() == nums.length){
        res.add(new ArrayList(path));
        return;
    }
    for(int i = 0;i<nums.length;i++){
        if(used[i]){//当前元素被使用了
            continue;
        }
        //正常逻辑
        path.add(nums[i]);
        used[i] = true;
        backTracking(nums);
        //回溯
        path.removeLast();
        used[i] = false;
    }
    }
}

2023.4.12 全排列Ⅱ

全排列的去重操作!

47. 全排列 II - 力扣(LeetCode)

class Solution {
    List<List<Integer>> res = 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 res;
    }
    public void backTracking(int[] nums){
        if(path.size() == nums.length){
            res.add(new ArrayList(path));
            return;
        }
        for(int i = 0;i<nums.length;i++){
            if(used[i]){//全排列防止重复
            continue;
            }
            if(i > 0 && nums[i] == nums[i-1] && used[i-1] == false){//去重
            continue;
            }
            used[i] = true;
            path.add(nums[i]);
            backTracking(nums);
            path.removeLast();
            used[i] = false;
        }
    }
}

最关键的一步判断

i > 0 && nums[i] == nums[i-1] && used[i-1] == false

这个used[i-1] == false 是用来判断同一层的去重的,如果不加这个语句,会出现错误!

因此如果只有前面的语句的话,由于排列没有start索引,它会分不清这是同一层还是同一个树枝,导致在同一个树枝下出现重复元素也会导致去重处理,因此排列的去重需要格外注意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值