代码随想录算法训练营第29天(回溯算法05 | * 491.递增子序列 * 46.全排列 * 47.全排列 II
回溯算法part05
- 491.递增子序列
- 解题思路
- 与` 90.子集II `不同的点
- 回溯三部曲
- 46.全排列
- 解题思路
- 遇到的难点
- 思考
- 47.全排列 II
- 解题思路
- 注意点
- 拓展
- 需要加深理解的点(需复习
- 小总结
491.递增子序列
本题和大家刚做过的
90.子集II非常像,但又很不一样,很容易掉坑里。
题目链接: 491.递增子序列
文章讲解: 491.递增子序列
视频讲解: 491.递增子序列
解题思路
在90.子集II中我们是通过排序,再加一个标记数组来达到去重的目的。
而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。
与90.子集II不同的点
- 不能排序
- 不能用之前的used[]数组,而要用set,且set不需要跟着回溯,只负责本层里面取了哪些元素
- 需要判断每个path中元素个数是否大于等于2
- 需要判断每个path是否是递增的
回溯三部曲
- 递归函数参数:
- 全局变量result和path
- startIndex
- 终止条件:
要遍历整个树,可以没有 - 单层遍历逻辑
- 去重逻辑
- 局部变量HashSet uset; 记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层!

// uset用数组实现 效率高一些
class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new LinkedList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}public void backTracking(int[] nums, int startIndex){if(path.size() >= 2){result.add(new ArrayList<>(path));}if(startIndex >= nums.length){ // 这个终止条件可以没有,因为我们要遍历整个树return;}int[] uset = new int[201];for(int i = startIndex; i <nums.length; i++){if(!path.isEmpty() && path.get(path.size() - 1) > nums[i] || uset[nums[i] + 100] == 1) continue; //注意是continue而不是breakuset[nums[i] + 100] = 1;path.add(nums[i]);backTracking(nums, i + 1);path.remove(path.size() - 1);}}
}
// // uset用set实现
class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new LinkedList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}public void backTracking(int[] nums, int startIndex){if(path.size() >= 2){result.add(new ArrayList<>(path));}if(startIndex >= nums.length){ // 这个终止条件可以没有,因为我们要遍历整个树return;}HashSet<Integer> uset = new HashSet<>();for(int i = startIndex; i <nums.length; i++){if(!path.isEmpty() && path.get(path.size() - 1) > nums[i] || uset.contains(nums[i])) continue; //注意是continue而不是breakuset.add(nums[i]);path.add(nums[i]);backTracking(nums, i + 1);path.removeLast();}}
}
46.全排列
本题重点感受一下,排列问题 与 组合问题,组合总和,子集问题的区别。 为什么排列问题不用 startIndex
题目链接: 46.全排列
文章讲解: 46.全排列
视频讲解: 46.全排列
解题思路
不需要i = startIndex控制for循环开始位置,每次从i = 0开始
需要判断当前元素是否已经取过
遇到的难点
如何不重复取自身元素:used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次
思考
这道题的used数组和之前题目中的used数组作用的不同
- 这道题的used数组:记录此时path里都有哪些元素使用了
- 之前题目中的used数组:树层上对组合去重,一般要先将数组排序

// 解法1:通过判断path中是否存在数字,排除已经选择的数字
// 感觉这种比解法2好理解
class Solution {List<List<Integer>> result = new ArrayList<>();LinkedList<Integer> path = new LinkedList<>();public List<List<Integer>> permute(int[] nums) {if (nums.length == 0) return result;backtrack(nums, path);return result;}public void backtrack(int[] nums, LinkedList<Integer> path) {if (path.size() == nums.length) {result.add(new ArrayList<>(path));}for (int i =0; i < nums.length; i++) {// 如果path中已有,则跳过if (path.contains(nums[i])) {continue;} path.add(nums[i]);backtrack(nums, path);path.removeLast();}}
}
// 法2:通过used判断是否path中已取过当前数字
class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new LinkedList<>();boolean[] used;public List<List<Integer>> permute(int[] nums) {used = new boolean[nums.length];backTracking(nums);return result;}public void backTracking(int[] nums){if(path.size() == nums.length){result.add(new ArrayList<>(path));}for(int i = 0; i < nums.length; i++){if(used[i]){continue;}used[i] = true;path.add(nums[i]);backTracking(nums);used[i] = false;path.removeLast();}}
}
47.全排列 II
本题 就是我们讲过的
40.组合总和II去重逻辑 和46.全排列的结合,可以先自己做一下,然后重点看一下 文章中 我讲的拓展内容。 used[i - 1] == true 也行,used[i - 1] == false 也行
题目链接: 47.全排列 II
文章讲解: 47.全排列 II
视频讲解: 47.全排列 II
解题思路
40.组合总和II去重逻辑 和46.全排列的结合
注意点
nums数组排序
Arrays.sort(nums);
树层去重
if(i > 0 && nums[i - 1] == nums[i] && used[i - 1] == false) continue; // 树层去重
取过的元素不再重复取
if(used[i] == true) continue; // 取过的数标记为1
拓展
去重代码中,如果改成 used[i - 1] == true, 也是正确的!
这是为什么呢,就是上面我刚说的,如果要对树层中前一位去重,就用used[i - 1] == false,如果要对树枝前一位去重用used[i - 1] == true。
对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
树枝去重图例

需要加深理解的点(需复习
- 树层去重和树枝去重
- used数组在不同题中的作用
- 为什么这道题的used数组需要作为参数参与递归结合
40.组合总和II和90.子集II进行思考 491.递增子序列中的uset

小总结
491.递增子序列 不能用之前的used[]数组,而要用set,且set不需要跟着回溯,只负责本层里面取了哪些元素 used数组不需要回溯,不需要放在递归参数里面
46.全排列 used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次 used数组要回溯,要放在递归参数里面
47.全排列 II used数组:去重+取过的元素不再重复取 used数组要回溯,要放在递归参数里面
class Solution {List<List<Integer>> result = new ArrayList<>();List<Integer> path = new LinkedList<>();boolean[] used;public List<List<Integer>> permuteUnique(int[] nums) {used = new boolean[nums.length];Arrays.sort(nums);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(i > 0 && nums[i - 1] == nums[i] && used[i - 1] == false) continue; // 树层去重if(used[i] == true) continue; // 取过的数标记为1used[i] = true;path.add(nums[i]);backTracking(nums, used);used[i] = false;path.removeLast();}}
}
相关文章:
代码随想录算法训练营第29天(回溯算法05 | * 491.递增子序列 * 46.全排列 * 47.全排列 II
回溯算法part05 491.递增子序列解题思路与 90.子集II 不同的点回溯三部曲 46.全排列解题思路遇到的难点思考 47.全排列 II解题思路注意点拓展需要加深理解的点(需复习 小总结 491.递增子序列 本题和大家刚做过的90.子集II非常像,但又很不一样,…...
mac docker desktop被禁用了,如何使用虚拟机lima运行docker
安装lima brew install lima创建配置 echo "\\ndynamic:\n big-sur:\n image: docker://docker:git\n linux:\n image: docker.io/limasoftware/ubuntu:20.04 \\n" > ~/.lima/default.yaml启动名叫default的虚拟机 limactl start default测试 limactl …...
sublime text 开启vim模式
sublime text 开启vim模式 打开配置文件 mac下点击菜单栏 Sublime Text -> Settings... -> Settings 修改配置文件并保存 添加配置 // 开启vim模式 "ignored_packages": [// "Vintage", ], // 以命令模式打开文件 "vintage_start_in_comman…...
JS词法结构
编程语言的词法结构是一套基础性规则,用来描述如何使用这门语言来编写程序。作为语法的基础,它规定了诸如变量名是什么样的、怎么写注释,以及程序语句之间如何分隔等规则。 2.1程序的文本 JS区分大小写 JS忽略程序记号(token&am…...
程序媛的mac修炼手册-- 如何用Python节省WPS会员费
上篇分享了如何用微博爬虫,咱举例爬了女明星江疏影的微博数据。今天就用这些数据,给大家安利一下怎么用Python实现WPS中部分Excel付费功能。 MacOS系统自带的工具,绝大多数都非常顶,除Numbers外。当然,page比起word来&…...
ASP.NET Core NE8实现HTTP Upgrade和HTTP CONNECT代理服务器
看到一个文章[Go] 不到 100 行代码实现一个支持 CONNECT 动词的 HTTP 服务器 在NET8中如何实现 创建项目为MiniApi 编辑Program.cs文件。 var builder WebApplication.CreateSlimBuilder(args);var app builder.Build();// 将HTTP请求通过协议升级机制转为远程TCP请求&…...
apipost和curl收不到服务器响应的HTTP/1.1 404 Not Found
windows的apipost发送请求后,服务器响应了HTTP/1.1 404 Not Found,但是apipost一直显示发送中。 linux上的curl也一样。 使用wireshark抓包发现收到了响应,但是wireshark识别不了(图中是回应404后关闭了连接)ÿ…...
javascript:计算一个坐标数组的最小值点、最大值点、中心点
作者:CSDN _乐多_ 本文将介绍使用 javascript 语言计算一个坐标数组的最小值点、最大值点、中心点的代码。 文章目录 一、代码 一、代码 function calculateCenterPoint(points) {if (points.length 0) {return null;}let sumX 0;let sumY 0;let sumZ 0;for …...
使用远程工具连接Linux系统——使用Root用户登录
1、启动虚拟机,输入以下命令 进入root用户 sudo su或 su root修改ssh配置文件 vim /etc/ssh/sshd_config找到PermitRootLogin 并用#注释掉当前行 # PermitRootLogin prohibit-password添加: PermitRootLogin yes键入esc输入:wq保存退出 2、重启服…...
JuiceSSH结合内网穿透实现移动端设备公网远程访问Linux虚拟机
文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …...
06-枚举和模式匹配
上一篇:05-使用结构体构建相关数据 在本章中,我们将介绍枚举。枚举允许你通过枚举其可能的变体来定义一种类型。首先,我们将定义并使用一个枚举,以展示枚举如何与数据一起编码意义。接下来,我们将探索一个特别有用的枚…...
【C/C++】C/C++编程——C++ 开发环境搭建
C的开发环境种类繁多,以下是一些常见的C 集成开发环境: AppCode :构建与JetBrains’ IntelliJ IDEA 平台上的用于Objective-C,C,C,Java和Java开发的集成开发环境CLion:来自JetBrains的跨平台的C/C的集成开…...
Go 接口
接口概览 接口大概理解 接口类型是队其他类型行为的概括与抽象 接口类型中,包含函数声明,但没有数据变量接口的作用通过使用接口,可以写出更加灵活和通用的函数,这些函数不用绑定在一个特定的类型实现上Go 接口特征 很多面向对象…...
用 AI 将自拍照 P 进不同艺术作品,谷歌发布「艺术自拍 2」
1 月 24 日消息,谷歌旗下「艺术与文化」应用今日宣布,2018 年推出的「艺术自拍」功能在时隔近六年后,借助生成式 AI 的力量回归。官方表示,「艺术自拍 2」将再次使用户与艺术面对面,重新探访世界各地的艺术、历史和文化…...
SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心
目录 1. OAuth2.0 简介 2. 代码搭建 2.1 认证中心(8080端口) 2.2 资源服务中心(8081端口) 3. 测试结果 1. OAuth2.0 简介 OAuth 2.0(开放授权 2.0)是一个开放标准,用于授权第三方应用程序…...
c# 策略模式
在 C# 中,策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装到具有公共接口的独立类中,使得它们可以互相替换。这样可以使得算法的选择独立于算法的使用者,从而提高了灵活性和可维护性。 以下是策略…...
消息队列RabbitMQ.03.死信交换机的讲解与使用
目录 一、死信队列(延迟队列) 概念讲解 二、确认消息(局部方法处理消息) 三、代码实战 1.编写生产者代码,配置消息、直连交换机、路由键 1.1代码解析: 2.配置消费者接受类接受直连交换机的路由键 2.1. String msgÿ…...
人工智能原理实验4(2)——贝叶斯、决策求解汽车评估数据集
🧡🧡实验内容🧡🧡 汽车数据集 车子具有 buying,maint,doors,persons,lug_boot and safety六种属性,而车子的好坏分为uncc,ucc,good and vgood四种。 🧡🧡贝叶斯求解🧡🧡…...
算力网络:未来计算资源的驱动力
文章目录 前言一、算力网络的基本概况(一)算力网络的基本概念(二)算力网络研究进展二、运营商的算力网络架构(一)算力网络基础设施构成(二)算力网络编排管理(三)能力开放三、算力网络的优势(一)弹性计算(二)降低成本(三)去中心化四、算力网络的应用场景(一)人…...
java动态导入excel按照表头生成数据库表
1、创建接口接收文件 //controller层 PostMapping("/importExcel1")public void importExcel1(HttpServletRequest request, MultipartFile file) {try {waterMeterService.importExcel1(request,file);} catch (Exception e) {throw new RuntimeException(e);}}//se…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
