代码随想录算法训练营day29 | 491.递增子序列,46.全排列,47.全排列 II

news2024/11/14 21:22:43

代码随想录算法训练营day29 | 491.递增子序列,46.全排列,47.全排列 II

  • 491.递增子序列
    • 解法一:回溯(map进行数层去重)
    • 解法二:回溯(仅针对本题,不具有普适性)
  • 46.全排列
    • 解法一:回溯(used数组记录去重,不是树层去重)
    • 解法二:回溯(根据path中是否含有该元素去重)
  • 47.全排列 II
    • 解法一:回溯
  • 总结


491.递增子序列

教程视频:https://www.bilibili.com/video/BV1EG4y1h78v/?vd_source=ddffd51aa532d23e6feac69924e20891
在这里插入图片描述本题的难点是不能排序,因此我们不能像90、子集II那样直接采用used数组记录使用情况,而应该采用map记录path中已经包含的数字进行数层去重。针对本题,因为nums中的数据范围有限,可以使用数组索引对应每一种数值来进行树层去重。

解法一:回溯(map进行数层去重)

//用map去重
class Solution {
    //结果集合
    List<List<Integer>> res = new ArrayList<>();
    //路径集合
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        getSubsequences(nums,0);
        return res;
    }
    private void getSubsequences( int[] nums, int start ) {
        if(path.size()>1 ){
            res.add( new ArrayList<>(path) );
            // 注意这里不要加return,要取树上的节点
        }
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=start ;i < nums.length ;i++){
            if(!path.isEmpty() && nums[i]< path.getLast()){
                continue;
            }
            // 使用过了当前数字
            if ( map.getOrDefault( nums[i],0 ) >=1 ){
                continue;
            }
            map.put(nums[i],map.getOrDefault( nums[i],0 )+1);
            path.add( nums[i] );
            getSubsequences( nums,i+1 );
            path.removeLast();
        }
    }
}
//用set去重
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;
    }

    
    public void backtracking(int[] nums, int startIndex){
        if(path.size()>1){
            result.add(new ArrayList<>(path));
        }
        //求子集可以不写终止条件
        if(startIndex>=nums.length){
            return;
        }

        Set<Integer> used = new HashSet<>();
        for(int i=startIndex; i<nums.length; i++){
            //树层去重
            if(used.contains(nums[i]) || (!path.isEmpty() && path.get(path.size()-1)>nums[i])){
                continue;
            }
            used.add(nums[i]);
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.remove(path.size()-1);
        }
    }
}

解法二:回溯(仅针对本题,不具有普适性)

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;
    }
    
    public void backtracking(int[] nums, int startIndex){
        if(path.size()>1){
            result.add(new ArrayList<>(path));
        }
        
        int[] used = new int[201];
        for(int i=startIndex;i<nums.length;i++){
            //前半部分是去除非递增子串,后半部分数层去重
            if((!path.isEmpty() && path.get(path.size()-1)>nums[i]) || (used[nums[i]+100]==1)){continue;}
            used[nums[i]+100]=1;
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.remove(path.size()-1);
        }
    }
}

46.全排列

教程视频:https://www.bilibili.com/video/BV19v4y1S79W/?spm_id_from=333.788&vd_source=ddffd51aa532d23e6feac69924e20891
在这里插入图片描述
这是排列问题,有两个需要关注的点:1、每层都是从0开始搜索而不是startIndex;2、需要记录path里都放了哪些元素了。

解法一:回溯(used数组记录去重,不是树层去重)

因为每层used要在上一层的基础上修改,因此used需要作为回溯参数传递。

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = 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(path.size()==nums.length){
            result.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,used);
            used[i]=false;
            path.remove(path.size()-1);
        }
    }
}

解法二:回溯(根据path中是否含有该元素去重)

针对本题nums中数值互不相同,可以根据path中是否含有该元素去重

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        backtracking(nums);
        return result;
    }
    public void backtracking(int[] nums){
        if(path.size()==nums.length){
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i=0;i<nums.length;i++){
            if(path.contains(nums[i])){
                continue;
            }
            path.add(nums[i]);
            backtracking(nums);
            path.remove(path.size()-1);
        }
    }
}

47.全排列 II

教程视频:https://www.bilibili.com/video/BV1R84y1i7Tm/?spm_id_from=pageDriver&vd_source=ddffd51aa532d23e6feac69924e20891
在这里插入图片描述

解法一:回溯

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        backtracking(nums,used);
        return result;
    }
 
    public void backtracking(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]控制在同一层去重
            if(i>0 && nums[i-1]==nums[i] && !used[i-1]){
                continue;
            }
            if(used[i]){
                continue;
            }
            path.add(nums[i]);
            used[i]=true;
            backtracking(nums,used);
            used[i]=false;
            path.remove(path.size()-1);
        }
    }
}

总结

1、不能排序时,需要采用Map进行树层去重。同时,求子集可以省略终止条件。
2、排列问题,有两个需要关注的点:a、每层都是从0开始搜索而不是startIndex;b、需要记录path里都放了哪些元素了。
3、47.全排列 II46.全排列40.组合总和II的结合。树枝不去重,树层去重。

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

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

相关文章

有一说一,这是我看到的全网最新最全的SpringBoot后端接口规范了

一、前言 一个后端接口大致分为四个部分组成&#xff1a;接口地址&#xff08;url&#xff09;、接口请求方式&#xff08;get、post等&#xff09;、请求数据&#xff08;request&#xff09;、响应数据&#xff08;response&#xff09;。虽然说后端接口的编写并没有统一规范…

一个.Net功能强大、易于使用、跨平台开源可视化图表

可视化图表运用是非常广泛的&#xff0c;比如BI系统、报表统计等。但是针对桌面应用的应用&#xff0c;很多报表都是收费的&#xff0c;今天给大家推荐一个免费.Net可视化开源的项目&#xff01; 项目简介 基于C#开发的功能强大、易于使用、跨平台高质量的可视化图表库&#…

Shiro 入门概述

目录 是什么 为什么要用 Shiro Shiro 与 SpringSecurity 的对比 基本功能 原理 是什么 Apache Shiro 是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完 成&#xff1a;认证、授权、加密、会话管理、与 Web 集成、缓存 等。借助 Shiro 您可以快速轻松 地保护…

Linux 中的文件锁定命令:flock、fcntl、lockfile、flockfile

在 Linux 系统中&#xff0c;文件锁定是一种对文件进行保护的方法&#xff0c;可以防止多个进程同时访问同一个文件&#xff0c;从而导致数据损坏或者冲突。文件锁定命令是一组用于在 Linux 系统中实现文件锁定操作的命令&#xff0c;它们可以用于对文件进行加锁或解锁&#xf…

直击中国国际金融展:实在智能携多项科技成果亮相,展现数字金融力量

4月25日-27日&#xff0c;中国国际金融展于北京首钢会展中心成功举办。作为我国规格最高、历史最久的金融科技展&#xff0c;本次展会以“荟萃金融科技成果&#xff0c;展现数字金融力量&#xff0c;谱写金融服务中国式现代化新篇章”为主题&#xff0c;吸引了众多国内金融机构…

企业邮箱选购,需关注哪些重要因素?

企业邮箱选择考虑哪些问题&#xff1f;应该从企业邮箱安全、企业邮箱的稳定性、企业邮箱专业、方便迁移到新的企业邮箱、企业邮箱邮件的到达率、功能强大的企业邮箱、企业邮箱手机客户端设置等方面考虑。 1.企业邮箱安全 企业邮箱应考虑病毒防治能力。Zoho Mail企业邮箱从物理安…

华硕笔记本系统更新后开机自动蓝屏怎么U盘重装系统?

华硕笔记本系统更新后开机自动蓝屏怎么U盘重装系统&#xff1f;有用户将自己的华硕笔记本进行系统升级之后&#xff0c;遇到了开机自动蓝屏的情况。遇到这个问题我们怎么去进行解决呢&#xff1f;接下来一起来看看怎么通过U盘重装系统的方法解决此问题吧。 准备工作&#xff1a…

【计算机组成原理】第五章 中央处理器

系列文章目录 第一章 计算系统概论 第二章 运算方法和运算器 第三章 多层次的存储器 第四章 指令系统 第五章 中央处理器 第六章 总线系统 第七章 外围设备 第八章 输入输出系统 文章目录 系列文章目录前言第五章 中央处理器5.1 CPU功能和组成5.1.1 CPU的功能5.1.2 CPU的基本…

中文修改润色平台-中文写作润色软件有哪些

中文语言润色软件 中文语言润色软件是一种基于自然语言处理技术&#xff0c;旨在提高中文文本的语言风格、表达能力和可读性的工具。中文语言润色软件可以自动检测和纠正文本中出现的语法、拼写、标点符号以及其他笔误等语言问题&#xff0c;并给出相应的纠正建议和修改意见。…

2022年5月、11月网络工程师真题详解

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 2022年5月网络工程师科目二真题 试题一&#xff1a; 某分支机构网络拓扑图如 1-1 所示&#xff0c;该网络通过 BGP 接收总部网络路由&#xff0c;设备 1 与设备…

AIGC产业研究报告 2023——音频生成篇

易观&#xff1a;今年以来&#xff0c;随着人工智能技术不断实现突破迭代&#xff0c;生成式AI的话题多次成为热门&#xff0c;而人工智能内容生成&#xff08;AIGC&#xff09;的产业发展、市场反应与相应监管要求也受到了广泛关注。为了更好地探寻其在各行业落地应用的可行性…

实战【7】手把手教你搭建属于自己的服务器

1 概述 最近总是想搭建自己的网站&#xff0c;奈何皮夹里空空如也&#xff0c;服务器也租不起&#xff0c;更别说域名了。于是我就寻思能否自己搭建个服务器&#xff0c;还不要钱呢&#xff1f; 经过几天的冲浪&#xff0c;我发现有两个免费的建站工具&#xff1a;Apache 和 …

MySQL 索引、事务与存储引擎

MySQL 索引 索引&#xff1a;根据查询字段在索引表中找到该行数据的物理地址。 作用&#xff1a;加快查询速度&#xff1b;排序。 缺点&#xff1a;占用额外的磁盘空间&#xff1b;更新一个包含索引的表需要花费更多的时间。 创建索引的原则 表的主键和外键需要索引&#…

Python每日一练(20230509) 石子游戏 IV\V\VI

目录 1. 石子游戏 Stone Game IV 2. 石子游戏 Stone Game V 3. 石子游戏 Stone Game VI &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 石子游戏 Stone Game IV Alice 和 Bob 两个人…

Halcon与Qt联合编程方法二(C++版本)

上一篇文章中提到基于python实现Halcon与Qt联合编程&#xff0c;但是在实际开发中&#xff0c;比如说已经有了qt编写的c版软件进行算法迭代&#xff0c;或者已经有了halcon编写的&#xff08;.hdev文件&#xff09;算法&#xff0c;想进行软件封装&#xff0c;这时候可以考虑把…

怎么把pdf中的某一页分出来?

怎么把pdf中的某一页分出来&#xff1f;PDF格式的文档在日常生活中是非常常见的&#xff0c;相信大家都对其有所了解&#xff0c;并且经常使用。它的主要特点是不允许用户随意编辑其中的内容&#xff0c;当我们仅需要阅读时&#xff0c;PDF文档无疑是十分方便的&#xff0c;尤其…

Linux Docker部署SpringCloud

Linux Docker部署SpringCloud 1 项目介绍2 快速部署2.1 api-registry2.1 api-gateway2.1 api-provider2.1 api-consumer 1 项目介绍 这是一个典型的springcloud项目架构&#xff0c;api-registry为注册中心&#xff0c;api-gateway为网关&#xff0c;api-provider为服务提供者&…

什么是域名流量劫持?

作为传统的互联网攻击方式&#xff0c;域名流量劫持已经十分常见&#xff0c;这种网络攻击将会在不经授权的情况下控制或重定向一个域名的DNS记录。域名劫持的影响难以估量&#xff0c;因为它可以导致在访问一个网站时&#xff0c;用户被引导到另一个不相关的网站&#xff0c;对…

uniapp collapse 一键收起

文章目录 前言一、源码二、方法1.部分代码2.原理 总结 前言 官方文档没有提供 说明&#xff0c;就研究源码&#xff0c;终于花了半上午的时间&#xff0c;找到了一种方法&#xff0c;可能不是很好用&#xff0c;但也可以用 一、源码 主要是这个方法&#xff0c;这个方法是用来…

劳动节程序员应该知道的知识——计算机

前言 现在AI崛起&#xff0c;计算机已经成为我们不可或缺的一部分&#xff0c;几乎在所有行业和领域都有广泛应用 。 五一已经快要过去了&#xff0c;程序员们应该都放假了&#xff0c;那我们是不是应该去了解了解我们的伙伴——计算机&#xff0c;了去解计算机是怎样工作的&am…