算法打卡day25|回溯法篇05|Leetcode 491.递增子序列、46.全排列、47.全排列 II

news2024/9/25 23:12:36

 算法题

Leetcode 491.递增子序列

题目链接:491.递增子序列

大佬视频讲解:递增子序列视频讲解

 个人思路

和昨天的子集2有点像,但昨天的题是通过排序,再加一个标记数组来达到去重的目的。

而本题求自增子序列,是不能对原数组进行排序的,因为排完序的数组都是自增子序列了。解决这道题还是用回溯法解决.

解法
回溯法

把递增子序列问题抽象为如下树形结构

回溯法三部曲

1.递归函数参数

本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。再加上结果列表和路径

2.终止条件

本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以可以不加终止条件,startIndex每次都会加1并不会无限递归。但本题收集结果有所不同,题目要求递增子序列大小至少为2.

3.单层搜索逻辑

 在图中可以看出,同一父节点下的同层上使用过的元素就不能再使用了,再加上题目中说了,数值范围[-100,100],所以这里可以用HashSet来记录同层是否重复使用元素

class Solution {
    List<List<Integer>> result = new ArrayList<>();//结果列表
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0);
        return result;
    }
    private void backTracking(int[] nums, int startIndex){
        if(path.size() >= 2) result.add(new ArrayList<>(path)); //收集结果
           
        HashSet<Integer> hs = new HashSet<>();//标记重复使用的元素,避免同层重复取元素

        for(int i = startIndex; i < nums.length; i++){
            if(!path.isEmpty() && path.get(path.size() -1 ) > nums[i] || hs.contains(nums[i]))
                continue;
            hs.add(nums[i]);
            path.add(nums[i]);
            backTracking(nums, i + 1);
            path.remove(path.size() - 1);//回溯
        }
    }
}

时间复杂度:O(n * 2^n));(循环n个元素,2^n表示所有可能的子集数量)

空间复杂度:O(n);(递归栈的深度最多为 n)


 Leetcode  46.全排列

题目链接:46.全排列

大佬视频讲解:全排列视频讲解

个人思路

这是典型的全排列问题,只能用for循环暴力再加回溯法解决。

解法
回溯法

以[1,2,3]为例,抽象成树形结构如下

回溯法三部曲

1.递归函数参数

首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。根据抽象出来的树形结构,可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。但排列问题需要一个used数组,标记已经选择的元素. 再加上结果列表和路径

2.递归终止条件

可以看出叶子节点,就是收割结果的地方。也就是当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。

3.单层搜索的逻辑

这里for循环里不用startIndex了。因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次

class Solution {

    List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
    boolean[] used;

    public List<List<Integer>> permute(int[] nums) {
        if (nums.length == 0){
            return result;
        }
        used = new boolean[nums.length];//初始化
        permuteHelper(nums);
        return result;
    }

    private void permuteHelper(int[] nums){
        if (path.size() == nums.length){//终止条件,收集叶子节点
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++){
            if (used[i]){//一个排列里一个元素只能使用一次
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            permuteHelper(nums);
            path.removeLast();//回溯
            used[i] = false;//回溯
        }
    }
}

时间复杂度:O(n!);(全排列)

空间复杂度:O(n);(递归栈的深度最多为 n)


 Leetcode  47.全排列 II

题目链接:47.全排列 II

大佬视频讲解:全排列 II视频讲解

 个人思路

这题和上题区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列。所以这里又涉及到去重了,依旧是树层不能重复取,树枝可以重复取

解法
回溯法

把 [1,1,2],抽象为如下树形结构

这道题的去重逻辑和 Leetcode  40.组合总和II 一样,搞清楚同一树层去重就能解决这道题。

这里注意一点:对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!

class Solution {
    
    List<List<Integer>> result = new ArrayList<>();//存放结果
    List<Integer> path = new ArrayList<>();//暂存结果

    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);//初始化

        Arrays.sort(nums);//排序 以方便去重
        backTrack(nums, used);
        return result;
    }

    private void backTrack(int[] nums, boolean[] used) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            // used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过
            // used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过

            // 如果同⼀树层nums[i - 1]使⽤过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }

            //如果同⼀树⽀nums[i]没使⽤过开始处理
            if (used[i] == false) {
                used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树枝重复使用
                path.add(nums[i]);
                backTrack(nums, used);
                path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
                used[i] = false;//回溯
            }
        }
    }
}

时间复杂度:O(n! * n);(全排列*可重复的元素)

空间复杂度:O(n);(递归栈的深度最多为 n)


 以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1539106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prometheus+Grafana 监控Tongweb7(by lqw)

文章目录 1.准备工作2.Tongweb7部署3.Prometheus部署4.上传jar包并配置Tongweb75.Prometheus配置6.安装和配置Grafana 1.准备工作 本次参考&#xff1a;Prometheus监控Tongweb容器 1.使用虚拟机ip&#xff1a;192.168.10.51&#xff08;tongweb&#xff09;&#xff0c;192.1…

oracle设置主键自增步骤

设置主键自增步骤&#xff1a; 每一张表都要设置序列&#xff0c;然后设置触发器。比mysql繁琐。 一、设置序列 选中表后&#xff0c;—》 文件—》新建—》其他—》序列. 设置如下四个值即可。 crtls保存。 给序列起个名字&#xff0c;一定要全大写字母。 二、设置触发器…

防火墙在解决方案及典型项目中的应用

防火墙在解决方案及典型项目中的应用 防火墙作为基础安全防护产品&#xff0c;在各种解决方案、业务场景中配套应用&#xff0c;本节给出各类方案资料链接方便查阅。 防火墙在华为网络解决方案中的应用 解决方案 文档 主要应用 CloudFabric云数据中心网解决方案 资料专区…

java设计模式(2)---六大原则

设计模式之六大原则 这篇博客非常有意义&#xff0c;希望自己能够理解的基础上&#xff0c;在实际开发中融入这些思想&#xff0c;运用里面的精髓。 先列出六大原则&#xff1a;单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特原则、开闭原则。 一、单一职…

Java中调用由C/C++实现的本地库(JNI本地程序调用)

文章目录 背景介绍什么是JNI&#xff1f;什么是本地库&#xff1f;开发Java使用JNI本地库步骤 编写Java类实现JNI本地调用windows系统下编译动态链接库创建Java项目&#xff08;demo&#xff09;第一步&#xff1a;编写带有native的Java类第二步&#xff1a;javac生成NativeDem…

C++的缺省参数,函数重载,引用

目录 1、缺省参数&#xff08;不能在函数声明和定义中同时出现&#xff0c;若声明和定义是分开的&#xff0c;则缺省参数放在声明里面&#xff09; 1.1、缺省参数的概念 1.2、全缺省 1.3、半缺省 2、函数重载 2.1、特殊情况 2.2、特殊情况 2.3、为什么C支持函数重载而C语…

springboot+itextpdf+thymeleaf+ognl根据静态模版文件实现动态生成pdf文件并导出demo

第一步&#xff1a;导入maven依赖 <!-- 导出为PDF依赖包 --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId></dependency><dependency><groupId>com.itextpdf</groupId><art…

网络安全慢速攻击

什么是低速缓慢攻击&#xff1f; 低速缓慢攻击是 DoS 或 DDoS 攻击的一种&#xff0c;依赖一小串非常慢的流量&#xff0c;可以针对应用程序或服务器资源发起攻击。与更传统的蛮力攻击不同&#xff0c;低速缓慢攻击所需的带宽非常小&#xff0c;并且难以防护&#xff0c;因为它…

Day60:WEB攻防-PHP反序列化POP链构造魔术方法流程漏洞触发条件属性修改

目录 PHP-DEMO1-序列化和反序列化 序列化操作 - 即类型转换 序列化案例 PHP-DEMO2-魔术方法触发规则 __construct(): //当对象new的时候会自动调用 __destruct()&#xff1a;//当对象被销毁时会被自动调用 __sleep(): //serialize()执行时被自动调用 __wakeup(): //uns…

程序员表白

啥&#xff1f;&#xff01;你说程序员老实&#xff0c;认真工作&#xff0c;根本不会什么表白&#xff01;那你就错了&#xff01;(除了我) 那今天我们就来讲一下这几个代码&#xff01;赶紧复制下来&#xff0c;这些代码肯定有你有用的时候&#xff01; 1.Python爱心代码 im…

MNN 执行推理(九)

系列文章目录 MNN createFromBuffer&#xff08;一&#xff09; MNN createRuntime&#xff08;二&#xff09; MNN createSession 之 Schedule&#xff08;三&#xff09; MNN createSession 之创建流水线后端&#xff08;四&#xff09; MNN Session 之维度计算&#xff08;五…

墨菲安全在软件供应链安全领域阶段性总结及思考

向外看&#xff1a;墨菲安全在软件供应链安全领域的一些洞察、思考、行动 洞察 现状&挑战&#xff1a; 过去开发安全体系是无法解决软件供应链安全问题的&#xff1b;一些过去专注开发安全领域的厂商正在错误的引导行业用开发安全思维解决软件供应链安全问题&#xff0c;治…

Linux:详解https协议

文章目录 什么是https协议信息窃取常见的加密数据摘要和数据指纹https的工作过程只使用对称加密只使用非对称加密都使用非对称加密非对称加密对称加密 证书数据签名https方案 本篇要总结的内容是关于https协议的相关内容 什么是https协议 在讲述https协议之前&#xff0c;首先…

Linux镜像文件下载地址--SCAS 开源镜像站,速度快

SCAS 开源镜像站 https://mirror.iscas.ac.cn/举例&#xff1a; 下载centos7 Index of /centos/7/isos/x86_64/ (iscas.ac.cn)

【C++算法】二分算法、二分模板详解,四道例题带详细注释

文章目录 [toc]1&#xff09;整数二分2&#xff09;解二分题步骤AcWing 789.数的范围洛谷 P1873.EKO/砍树洛谷 P1678.烦恼的高考志愿 2&#xff09;浮点二分AcWing 790. 数的三次方根 1&#xff09;整数二分 有单调性的题目一定可以二分&#xff0c;但是用二分做的题目不一定拥…

Linux初学(八)磁盘管理

一、磁盘管理 1.1 简介 磁盘的工作原理&#xff1a; 添加磁盘对磁盘进行分区格式化磁盘挂载和使用磁盘 磁盘的类型&#xff1a; 固态机械 磁盘的接口类型&#xff1a; IDESTSTSCSI 磁盘工作的原理&#xff1a; 磁盘&#xff0c;特别是硬盘&#xff0c;和内存不同&#xff0c;…

【Bug】记录2024年遇到的Bug以及修复方案

--------------------------------------------------------分割线 2024.3.22------------------------------------------------------- 1、load_sample_image raise AttributeError(“Cannot find sample image: %s” % image_name) AttributeError: Cannot find sample ima…

nvidia显卡如何安装cuda驱动

目录 查看显卡对应的cuda版本下载与你显卡匹配的CUDA Toolkit 查看显卡对应的cuda版本 按 微软 R 键&#xff0c;输入cmd 然后输入 nvidia-smi &#xff0c;回车显示下面信息&#xff1a; 看到 CUDA Version 为 12.2 下载与你显卡匹配的CUDA Toolkit 打开网页&#xff1a…

鸿蒙Harmony应用开发—ArkTS-@AnimatableExtend装饰器:定义可动画属性

AnimatableExtend装饰器用于自定义可动画的属性方法&#xff0c;在这个属性方法中修改组件不可动画的属性。在动画执行过程时&#xff0c;通过逐帧回调函数修改不可动画属性值&#xff0c;让不可动画属性也能实现动画效果。 可动画属性&#xff1a;如果一个属性方法在animation…

C++默认构造函数(二)

目录 构造函数补充 构造函数初始化列表的使用 赋值运算符重载函数 运算符重载函数介绍 运算符重载函数的使用 赋值运算符重载函数 赋值运算符重载函数的使用 拷贝构造函数和赋值运算符重载函数 重载前置和后置 前置 后置 重载流插入<<与流提取>> 流插…