代码随想录算法训练营第二十八天 | LeetCode 491. 递增子序列、46. 全排列、47. 全排列 II

代码随想录算法训练营第二十八天 | LeetCode 491. 递增子序列、46. 全排列、47. 全排列 II

文章链接:递增子序列        全排列        全排列II

视频链接:递增子序列        全排列        全排列II

目录

代码随想录算法训练营第二十八天 | LeetCode 491. 递增子序列、46. 全排列、47. 全排列 II

1. LeetCode 491. 递增子序列

1.1 思路

1.2 代码

2. LeetCode 46. 全排列

2.1 思路

2.2 代码

3. LeetCode 47. 全排列 II

3.1 思路

3.2 代码


1. LeetCode 491. 递增子序列

1.1 思路

  1. 这题和90. 子集 II很像,但是又有点不同,相同的是都是求子集并且是有重复元素的,并要求不能有重复组合,不同的是这题我们不可以给数组排序,因为要求的是自增子序列,自增就是要按照题目的顺序,并且元素个数是要>=2 的
  2. 而我们用回溯算法去求难免会有重复的元素,因此需要去重,而去重的逻辑又不能与40. 组合总和 II和90. 子集 II相同,因为不能排序。这题属于回溯算法和深搜都对,本质是差不多的,所有回溯都是深搜
  3. 与之前一样,还是树层去重,树枝上数值是可以取数值相同的元素的,树层上是不可以的。树枝上允许出现 [4,7,7] 这种情况,但树层上如果第二次取相同数值的元素其实在第一次取了之后往下递归的过程在树枝上已经取过第二个相同的元素了,因此要树层去重
  4. 这里收集结果的地方其实也是树上的节点,只是对结果里的元素数量有要求,要>=2 个,因此收集结果的地方依然是在回溯函数的首行,只是要加个条件,里面的元素要>=2
  5. 综上我们要去重的部分其实主要就是两部分,第一是这个树层上重复出现的元素,第二是该元素比子序列的最后一个元素小的情况
  6. 定义两个全局变量,result、path
  7. 回溯函数的参数和返回值:返回值 void,参数 nums,startIndex 控制剩余集合的起始位置
  8. 终止条件:startIndex>=nums.length
  9. 单层搜索的逻辑:进入递归就收集结果,因为每个节点都是我们的结果,但是本题需要判断一下,与元素个数要>=2,把 path 加入到 result 中
  10. 要先定义个 HashSet set,就是做树层去重的,我们怎么知道同层前面取过了某个元素接下来就不能取了呢?就用 set 记录一下,for(int i=startIndex;i<nums.length;i++),for循环每取一个就放入到 set 里,然后 for循环里判断如果要取的这个数已经在 set 里了就跳过此次循环。然后我们在取数时如果取的数比子序列最后一个元素小的话就不取,即 if( !path.isEmpty() && nums[i]<path.get(path.size()-1 || set.contains(nums[i]) )continue,这里的意思就是如果取的这个数比自序列最后一个元素小或者同一层已经取过这个数了就跳过,这里要加 !path.isEmpty() 因为集合为空会报异常。这里为什么是 continue 是因为这个元素不可以取了,下一个可能是能取的。
  11. 然后就是取数的过程,set.add(nums[i]),path.add(nums[i])。然后是递归 backtracking(nums, i+1),然后是回溯的过程 path.remove(path.size()-1)。这里为什么不需要把 set 也回溯呢?因为这个 set 只是记录同一层里是否取过某个数,而进入递归时是新创建一个 set,再重新记录同一层是否取过某个数,set 的作用就是记录当前这层递归的元素别取重复了

1.2 代码

//
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);}}
}

2. LeetCode 46. 全排列

2.1 思路

  1. 这题没有重复元素,因此不用考虑去重。这题是排列,需要清除与组合的区别。
  2. 这题需要用个 used 数组,之前都是用 used 来去重的,这里不需要去重为什么也用呢?这里是用 used 数组是标记哪个元素使用过了,我们求排列相同元素不能重复使用,和之前的去重逻辑是不一样的。做组合类问题时都是用 startIndex 来避免重复取同一个元素和出现 [1,2][2,1] 这种情况。
  3. 这题的结果都是在叶子节点上的,树的深度就是由集合的大小长度来控制的,因为最后取的排列就是和集合一样大的
  4. 定义三个全局变量,result、path、used 数组标记哪个元素已经使用过
  5. 回溯函数的参数和返回值:返回值 void,参数 nums
  6. 终止条件:当 nums.length==path.size()就把 path 加入到 result 中然后 return
  7. 单层搜索的逻辑:for(int i=0; i<nums.length; i++)这里为什么从 0 开始?因为之前用 startIndex 控制是为了避免重复,比如出现[1,2][2,1] 这种情况,而现在求排列 [1,2][2,1] 都是我们要的结果,因此每次取数都要从头开始,唯一要跳过的情况就是这一层取过这个数了,下一层就别取这个数了,也就是用 used 数组控制的。if(used[i]==true)就 continue,因为是 true 说明上一层用过了,就跳过此次循环。然后就是取数的过程,used[i]=true ,path.add(nums[i])。然后就是下一层递归了,backtracking(nums)。然后就是回溯,就是 used[i]=false,path.removeLast()

2.2 代码

//
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;}}
}

3. LeetCode 47. 全排列 II

3.1 思路

  1. 这题和46. 全排列的区别就是这题有重复元素,这样就会导致出现相同的排列不如两个{1,1,2},因此要去重(注意这里去重需要先对题目的数组排序,因为要让相同的元素挨在一起)。同时这里也需要 used 数组标记哪些元素是否使用过,避免出现了使用两次同一个元素
  2. 依然是从树层去重和树枝去重的角度看。同一树层上,前面取过 1 后面就不能取 1 了,因为剩余集合是相同的,再取一次就会得到相同的排列,就重复了。而在同一树枝上上面取过 1 了,下面还可以取 1,这里没有重复取 1,上面取的是第一个 1 下面取的是第二个 1,这里是两个元素,排列里可以出现比如{1,1,2}这样子可以出现两个数值相同的元素。而结果是在叶子节点上,我们要砍去的分支都是在树层上如果和前面的树枝相同就要砍掉
  3. 定义三个全局变量,result、path、used 数组标记哪个元素已经使用过
  4. 回溯参数的参数和返回值:返回值 void,参数 nums
  5. 终止条件:当 path.size()==nums.length 就把 path 加入到 result 中然后 return
  6. 单层搜索的逻辑:for(int i=0; i<nums.length; i++)这里为什么从 0 开始?因为之前用 startIndex 控制是为了避免重复,比如出现[1,2][2,1] 这种情况,而现在求排列 [1,2][2,1] 都是我们要的结果,因此每次取数都要从头开始。而取数时有些不能取的,(i>0&&nums[i-1]==nums[i]&&used[i-1]==false)i>0 避免数组越界,然后树层上遇到相同元素就砍掉后面的分支,如果知道是树层而不是树枝呢?used[i-1]=false 就是树层,true 就是树枝,因为是回溯过来往树层右边取的。如果这个括号的条件为 true 就 continue 跳过此次循环,就是继续往树层右边搜索
  7. 然后是挨个取数的逻辑,取数时 if(used[i]==true)就 continue,这个情况就是排列里不能取同一个数的逻辑。然后就继续取数,used[i]=true,path.add(nums[i]),然后递归函数,然后回溯 used[i]=false,path.removeLast()

3.2 代码

//
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;//回溯}}}
}

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

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

相关文章

ArrayDeque 源码解析(JDK1.8)

目录 一. 前言 二. 源码解析 2.1. 概览 2.2. 属性 2.3. 构造方法 2.4. 入队 2.4.1. addFirst(E, e) 2.4.2. add(E e) & addLast(E e) 2.4.3. offer(E e) 2.5. 扩容 2.6. 出队 2.6.1. poll() & pollFirst() 2.6.2. pollLast() 2.7. 删除元素 2.8. 获取元…

【学习笔记】RabbitMQ01:基础概念认识以及快速部署

参考资料 RabbitMQ官方网站RabbitMQ官方文档噼咔噼咔-动力节点教程 文章目录 一、认识RabbitMQ1.1 消息中间件&#xff08;MQ Message Queue 消息队列1.2 主流的消息中间件1.3 MQ的应用场景1.3.1 异步处理1.3.2 系统解耦1.3.3 流量削峰1.3.4 日志处理 二、RabbitMQ运行环境搭建…

驱动开发day2

任务&#xff1a;使用模块化编译安装驱动实现三盏LED灯的亮灭 驱动程序 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h>#define PHY_RCC 0X50000A28 #define PH…

神经网络中的反向传播:综合指南

塔曼纳 一、说明 反向传播是人工神经网络 &#xff08;ANN&#xff09; 中用于训练深度学习模型的流行算法。它是一种监督学习技术&#xff0c;用于调整网络中神经元的权重&#xff0c;以最小化预测输出和实际输出之间的误差。 在神经网络中&#xff0c;反向传播是计算损失函数…

基于 Qt UDP通信局域网通信

前言 该例程经过实际验证可以正常使用,只简单的使用UDP中的单播模式(一对一), 所用测试系统在同一局域网,其中: QT版本:5.12 PC端UDP模式:单播 UDP通信目标:基于STM32F4+LWIP协议的以太网接口 调试助手: 虚拟串口+串口助手+UDP和TCP调试助手[编程人员必备]一、UDP通…

MySQL数据库下载与安装使用

文章目录 MySQL数据库下面是各个版本完整的生命周期。下载MySQL安装包安装和使用MySQL一些基础MySQL使用命令 MySQL数据库 这里我选择的是免安装绿色解压版本 现在各位开发者使用的MySQL&#xff0c;大部分版本都是 5.7&#xff0c;根据官方说明&#xff0c;MySQL 5.7 将于 202…

18.项目开发之前端项目搭建测试

项目开发之前端项目搭建测试 解压文件&#xff0c;将前端项目目录&#xff0c;拖拽到HBuilder中 前端项目QuantTrade_vue地址&#xff1a;传送门 后端项目QuantTrade地址&#xff1a; https://pan.baidu.com/s/1GF45B0QepApH8JbRIOLY7w?pwd1016 开启idea的项目&#xff0c;先…

智慧油气田方案:视频+AI识别,助力油气田生产与管理智能化转型

一、背景与挑战 根据《“十四五”能源领域科技创新规划》指出&#xff0c;要推动核心技术创新突破&#xff0c;推动煤炭、油田、电厂、电网等传统行业与数字化、智能化技术深度融合。我国油田产业已经摆脱了早期粗放式增长的阶段&#xff0c;需要更加精细化、智慧化、科学化的…

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息&#xff1a;1.2 基本信息&#xff1a;1.2.1 软件支持的内容&#xff1a;1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具&#xff0c;主要是…

django建站过程(2)创建第一个应用程序页面

创建第一个应用程序页面 设置第一个页面【settings.py,urls.py,views.py】settings.pyurls.pyviews.py django是由一系列应用程序组成&#xff0c;协同工作&#xff0c;让项目成为一个整体。前面已创建了一个应用程序baseapp,使用的命令 python manage.py startapp baseapps这…

机器学习,神经网络中,自注意力跟卷积神经网络之间有什么样的差异或者关联?

如图 6.38a 所示&#xff0c;如果用自注意力来处理一张图像&#xff0c;假设红色框内的“1”是要考虑的像素&#xff0c;它会产生查询&#xff0c;其他像素产生 图 6.37 使用自注意力处理图像 键。在做内积的时候&#xff0c;考虑的不是一个小的范围&#xff0c;而是整张图像的…

发展新能源汽车加快充换电基础设施建设实施方案-安科瑞黄安南

摘要&#xff1a;为深入贯彻落实《国务院办公厅关于印发新能源汽车产业发展规划&#xff08;2021—2035年&#xff09;的通知》&#xff08;国办发 ﹝2020﹞39号&#xff09;、《国家发展改革委等部门关于进一步提升电动汽车充电基础设施服务保障能力的实施意见》&#xff08;发…

【电子通识】USB接口三大类型图册

基本概念 不同时期的USB接口有不同的类型&#xff0c;USB接口分为插头和插座&#xff1a; 插头&#xff0c;plug&#xff0c;对应的也叫公口&#xff0c;即插别人的。 插座&#xff0c;receptacle&#xff0c;对应也叫做母口&#xff0c;即被插的。 USB的接口类型&#xff0…

VMware下linux中ping报错unknown host的解决办法

一、错误截图 二、解决办法 2.1 按照步骤查看本机虚拟IP 依次点击&#xff1a;【编辑】》【虚拟网络编辑器】&#xff0c;选中NET模式所属的行&#xff0c;就能看到子网地址。 比喻&#xff0c;我的子网地址是&#xff1a;192.168.18.0 那么&#xff0c;接下来要配置的linux…

根据pid查看jar包(windows)

打开jdk/bin/jvisualvm.exe,根据pid找到jar包的主启动类,jdk14以后不再默认使用,官网下载,也可以使用老版本的查看

如果Domino上的邮件无法直接发送到@outlook.com

大家好&#xff0c;才是真的好。 目前将Domino仅仅作为邮件服务器的企业用户还不少。如果Domino服务器版本比较新&#xff08;例如版本为11.0.x、12.0.x等&#xff09;&#xff0c;外发邮件时&#xff0c;没有通过邮件网关中转邮件&#xff0c;而是直接发送到Internet互联网上…

未来数字化转型发展的前景如何,企业又该怎么实现?

商业世界有一个认识&#xff0c;互联网只用看中国和美国&#xff0c;其他国家已经被远远甩在了后边&#xff0c;移动互联网的出现更是将互联网的跨地域、跨国、互联等属性发挥到了极致&#xff0c;让众多互联网巨头开启了争夺世界各国市场的脚步。 移动互联网的飞速发展以及物…

VMware——Window11安装VMware17(图解版)

目录 一、VMware17百度云下载二、安装三、注册 一、VMware17百度云下载 下载链接&#xff1a;https://pan.baidu.com/s/1dv_Y7ig2LUFxeHvrG2rOTA 提取码&#xff1a;elih 二、安装 下载 VMware-workstation-full-17.0.2-21581411.exe 安装包后&#xff0c;右键以管理员身份运…

软考-访问控制技术原理与应用

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 访问控制概念 访问控制是计算机安全的一个重要组成部分&#xff0c;用于控制用户或程序如…

PHP的学习入门建议

学习入门PHP的步骤如下&#xff1a; 确定学习PHP的目的和需求&#xff0c;例如是为了开发网站还是为了与数据库交互等。学习PHP的基础语法和程序结构&#xff0c;包括变量、数据类型、循环、条件等。学习PHP的面向对象编程&#xff08;OOP&#xff09;概念和技术。学习与MySQL…