Leetcoder Day25| 回溯part05:子集+排列

491.递增子序列

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

  • 输入:4, 7, 6, 7
  • 输出: \[4, 6, 4, 7, 4, 6, 7, 6, 7, 7,7, 4,7,7]

说明:

  • 给定数组的长度不会超过15。
  • 数组中的整数范围是 -100,100
  • 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

在子集中我们是通过排序,再加一个标记数组来达到去重的目的。而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。**所以不能使用之前的去重逻辑。**本题抽象为树结构过程如下:

从上图可以看到,如果在同一个父节点下,同一树层使用过的元素便不再取,如果所取元素小于子序列最后一个元素,也不符合条件。因此,可以设置一个哈希集合,来记录当前所取的值是否被使用过,哈希集合在递归后不用回溯,因为记录的是同一树层的使用情况,新的循环会清空重新记录。

java 复制代码
class Solution {
    List<List<Integer>> res =new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public void backTracking(int[] nums, int startIdx){
        if(path.size()>1){
            res.add(new ArrayList<>(path));
        }
        HashSet record= new HashSet<>();
        for(int i=startIdx;i<nums.length;i++){
            /*
            如果path不为空且当前元素小于path最后一个元素,则不取
            如果元素的值使用过,不取
             */
            if((!path.isEmpty() &&  path.get(path.size()-1)>nums[i]) || record.contains(nums[i])){
                continue;
            }
            record.add(nums[i]);
            path.add(nums[i]);
            backTracking(nums, i+1);
            path.removeLast();
        }

    }
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0);
        return res;
    }
}

46.全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

  • 输入: 1,2,3
  • 输出: \[1,2,3, 1,3,2, 2,1,3, 2,3,1, 3,1,2, 3,2,1 ]

排列问题不需要使用startIdx因为可以存在重复取值的情况,比如第一次1被取过,形成1,2,3,后面还可以再取组成2,1,3,但是需要设置一个数组used来记录当前元素在同一path中是否使用过。如果usedi-1为true,则取下一个元素,因为本题为不重复的元素,所以不用去重。

java 复制代码
class Solution {
    List<List<Integer>> res =new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    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++){
            /* 
            如果used[i-1]为true,说明同一树枝上使用过值一样的元素
            如果used[i-1]为false,说明同一树层上使用过值一样的元素
            */
            if(used[i]==true) continue;
            used[i]=true;
            path.add(nums[i]);
            backTracking(nums, used);
            path.removeLast();
            used[i]=false;
        }

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

📢注意:在调用回溯算法的时候,要记得创建一个used数组。

47.全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

  • 输入:nums = 1,1,2
  • 输出: \[1,1,2, 1,2,1, 2,1,1]

示例 2:

  • 输入:nums = 1,2,3
  • 输出:\[1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1]

本题和上一题的区别在于有重复的数字,所以需要去重,先对数组进行排序,设置used数组记录是否使用过如果usedi-1为true,说明同一树枝上使用过值一样的元素;如果usedi-1为false,说明同一树层上使用过值一样的元素。

java 复制代码
import java.util.Arrays;
class Solution {
    List<List<Integer>> res =new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    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++){
            /*
            当 used[i-1]== used[i]时
            used[i-1]为true,说明同一树枝使用过
            若为false,说明同一树层使用过
             */
            if(used[i]==true || (i>0 && nums[i-1]==nums[i] && used[i-1]==false)){
                continue;
            }
            used[i]=true;
            path.add(nums[i]);
            backTracking(nums, used);
            path.removeLast();
            used[i]=false;
        }

    }
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);
        used=new boolean[nums.length];
        backTracking(nums, used);
        return res;
    }
}
相关推荐
浮芷.8 分钟前
鸿蒙 6.1 新特性-60fps流畅人物跳跃功能算法深度解析-鸿蒙PC端正弦值计算法
算法·华为·harmonyos·鸿蒙·鸿蒙系统
AI科技星11 分钟前
数术工坊·第八卷 大道归一录・番外・下篇 零界封神・万法归元终章
网络·人工智能·算法·几何学·拓扑学
Misnearch17 分钟前
Leetcode热题100
算法·leetcode·职场和发展
悠仁さん23 分钟前
数据结构 图(概念篇)
数据结构
带土125 分钟前
1. 数据结构简单复习回顾(线性结构)
数据结构
我是一颗柠檬29 分钟前
【Java项目技术亮点】滑动窗口限流算法
java·开发语言·算法
无限码力33 分钟前
华为非AI方向笔试真题 - 楼内救人
算法·华为·华为非ai方向笔试真题·华为笔试真题·华为算法题
一切皆是因缘际会33 分钟前
隐层表征解构:LLM感知式幻觉稀疏成因
算法·数学建模·ai·架构
Irissgwe33 分钟前
二叉树进阶
数据结构·c++·算法·c·二叉搜索树
无限码力35 分钟前
华为非AI方向笔试真题 - 容器镜像平均大小统计
算法·华为·华为非ai方向笔试真题·华为笔试真题·华为非ai笔试真题·华为0612非ai笔试真题