代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II
491.递增子序列
卡哥建议:本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。
视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v
做题思路:
在90.子集II中我们是通过排序,再加一个标记数组来达到去重的目的。
而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。所以不能使用之前的去重逻辑!
用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:

还得有树层去重,如上图的同一父节点不能重复使用7,同一父节点下的同层上使用过的元素就不能再使用了
 关于uset,是记录本层元素是否重复使用,详细的看卡哥视频吧
本题代码:
 1 class Solution {
 2 private:
 3     vector<vector<int>> result;
 4     vector<int> path;
 5     void backtracking(vector<int>& nums, int startIndex) {
 6         if (path.size() > 1) {
 7             result.push_back(path);
 8         }
 9         int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
10         for (int i = startIndex; i < nums.size(); i++) {
11             if ((!path.empty() && nums[i] < path.back())
12                     || used[nums[i] + 100] == 1) {
13                     continue;
14             }
15             used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了
16             path.push_back(nums[i]);
17             backtracking(nums, i + 1);
18             path.pop_back();
19         }
20     }
21 public:
22     vector<vector<int>> findSubsequences(vector<int>& nums) {
23         result.clear();
24         path.clear();
25         backtracking(nums, 0);
26         return result;
27     }
28 };
46.全排列
卡哥建议:本题重点感受一下,排列问题 与 组合问题,组合总和,子集问题的区别。 为什么排列问题不用 startIndex
视频讲解:https://www.bilibili.com/video/BV19v4y1S79W
做题思路:
以[1,2,3]为例,抽象成树形结构如下:

首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。
可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。
但排列问题需要一个used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。如图橘黄色部分所示。
可以看出叶子节点,就是收割结果的地方。那么什么时候,算是到达叶子节点呢?
当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。
本题代码:
 1 class Solution {
 2 public:
 3     vector<vector<int>> result;
 4     vector<int> path;
 5     void backtracking (vector<int>& nums, vector<bool>& used) {
 6         // 此时说明找到了一组
 7         if (path.size() == nums.size()) {
 8             result.push_back(path);
 9             return;
10         }
11         for (int i = 0; i < nums.size(); i++) {
12             if (used[i] == true) continue; // path里已经收录的元素,直接跳过
13             used[i] = true;
14             path.push_back(nums[i]);
15             backtracking(nums, used);
16             path.pop_back();
17             used[i] = false;
18         }
19     }
20     vector<vector<int>> permute(vector<int>& nums) {
21         result.clear();
22         path.clear();
23         vector<bool> used(nums.size(), false);
24         backtracking(nums, used);
25         return result;
26     }
27 };
47.全排列 II
卡哥建议:本题 就是我们讲过的 40.组合总和II 去重逻辑 和 46.全排列 的结合,可以先自己做一下,然后重点看一下 文章中 我讲的拓展内容。 used[i - 1] == true 也行,used[i - 1] == false 也行
视频讲解:https://www.bilibili.com/video/BV1R84y1i7Tm
做题思路:
这道题目和46.全排列的区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列。
这里又涉及到去重了。
还要强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:

图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。
对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!看卡哥文章解释。
本题代码:
 1 class Solution {
 2 private:
 3     vector<vector<int>> result;
 4     vector<int> path;
 5     void backtracking (vector<int>& nums, vector<bool>& used) {
 6         // 此时说明找到了一组
 7         if (path.size() == nums.size()) {
 8             result.push_back(path);
 9             return;
10         }
11         for (int i = 0; i < nums.size(); i++) {
12             // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
13             // used[i - 1] == false,说明同一树层nums[i - 1]使用过
14             // 如果同一树层nums[i - 1]使用过则直接跳过
15             if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
16                 continue;
17             }
18             if (used[i] == false) {
19                 used[i] = true;
20                 path.push_back(nums[i]);
21                 backtracking(nums, used);
22                 path.pop_back();
23                 used[i] = false;
24             }
25         }
26     }
27 public:
28     vector<vector<int>> permuteUnique(vector<int>& nums) {
29         result.clear();
30         path.clear();
31         sort(nums.begin(), nums.end()); // 排序
32         vector<bool> used(nums.size(), false);
33         backtracking(nums, used);
34         return result;
35     }
36 };
代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II的更多相关文章
- 代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
		977.有序数组的平方 :https://leetcode.cn/problems/squares-of-a-sorted-array/ 心得:周末再写... public class Solutio ... 
- LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II
		欢迎关注个人公众号:爱喝可可牛奶 LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II LeetCode 491. 递增子序列 分析 找出并返回所有数组中不同的递增子序 ... 
- 代码随想录算法训练营day01 | leetcode 704/27
		前言 考研结束半个月了,自己也简单休整了一波,估了一下分,应该能进复试,但还是感觉不够托底.不管怎样,要把代码能力和八股捡起来了,正好看到卡哥有这个算法训练营,遂果断参加,为机试和日后求职打下一个 ... 
- 代码随想录算法训练营day02 | leetcode 977/209/59
		leetcode 977 分析1.0: 要求对平方后的int排序,而给定数组中元素可正可负,一开始有思维误区,觉得最小值一定在0左右徘徊,但数据可能并不包含0:遂继续思考,发现元素分布有三种情 ... 
- 代码随想录算法训练营day06 | leetcode 242、349 、202、1
		基础知识 哈希 常见的结构(不要忘记数组) 数组 set (集合) map(映射) 注意 哈希冲突 哈希函数 LeetCode 242 分析1.0 HashMap<Character, Inte ... 
- 代码随想录算法训练营day03 | LeetCode 203/707/206
		基础知识 数据结构初始化 // 链表节点定义 public class ListNode { // 结点的值 int val; // 下一个结点 ListNode next; // 节点的构造函数(无 ... 
- 代码随想录算法训练营day22 | leetcode 235. 二叉搜索树的最近公共祖先  ● 701.二叉搜索树中的插入操作  ● 450.删除二叉搜索树中的节点
		LeetCode 235. 二叉搜索树的最近公共祖先 分析1.0 二叉搜索树根节点元素值大小介于子树之间,所以只要找到第一个介于他俩之间的节点就行 class Solution { public T ... 
- 代码随想录算法训练营day18 | leetcode 513.找树左下角的值 ● 112. 路径总和  113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树
		LeetCode 513.找树左下角的值 分析1.0 二叉树的 最底层 最左边 节点的值,层序遍历获取最后一层首个节点值,记录每一层的首个节点,当没有下一层时,返回这个节点 class Solutio ... 
- 代码随想录算法训练营day17 | leetcode ● 110.平衡二叉树  ● 257. 二叉树的所有路径  ● 404.左叶子之和
		LeetCode 110.平衡二叉树 分析1.0 求左子树高度和右子树高度,若高度差>1,则返回false,所以我递归了两遍 class Solution { public boolean is ... 
- 代码随想录算法训练营day16 | leetcode ● 104.二叉树的最大深度  559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数
		基础知识 二叉树的多种遍历方式,每种遍历方式各有其特点 LeetCode 104.二叉树的最大深度 分析1.0 往下遍历深度++,往上回溯深度-- class Solution { int deep ... 
随机推荐
- UCOS-II 任务栈空间合理分配
			最近利用空闲时间跑了一下正点原子的stm32f4开发板的实时操作系统demo,发现了一个比较有意思的东西,分享如下: 硬件平台:正点原子stm32f4开发板 软件开发平台:MDK uVision v5 ... 
- vue使用iframe嵌入html,js方法互调
			前段时间 使用h5搞了个用cesium.js做的地图服务功能,后来想整合到vue项目,当然最简单的就是iframe直接拿来用了. 但html和vue的方法交互就是成了问题,vue调用html种方法还好 ... 
- Java 新的生态,Solon v2.3.2 发布
			Solon 是什么框架? 一个,Java 新的生态型应用开发框架.它从零开始构建,有自己的标准规范与开放生态(全球第二级别的生态).与其他框架相比,它解决了两个重要的痛点:启动慢,费资源. 解决痛点? ... 
- MySQL8新特性窗口函数详解
			本文博主给大家详细讲解一波 MySQL8 的新特性:窗口函数,相信大伙看完一定能有所收获. 本文提供的 sql 示例都是基于 MySQL8,由博主亲自执行确保可用 博主github地址:http:// ... 
- 自然语言处理 Paddle NLP - 文本翻译技术及应用-理论
			什么是机器翻译 机器翻译质量的自动评价 从统计机器翻译到神经网络机器翻译 多语言/多领域/多模态的翻译应用 神经网络机器翻译面临的挑战 视频:https://aistudio.baidu.com/ai ... 
- .NET Core 允许跨域的两种方式实现(IIS 配置、C# 代码实现)
			〇.前言 当把开发好的 WebApi 接口,部署到 Windows 服务器 IIS 后,postman 可以直接访问到接口并正确返回,这并不意味着任务完成,毕竟接口嘛是要有交互的,最常见的问题莫过于跨 ... 
- 在Linux环境下通过命令行执行JMeter脚本后查看响应结果的配置
			在Linux环境中进行性能测试时,我们可能会遇到一定程度的报错.如果无法打开JMeter的GUI界面,但又需要查看响应结果,可以按照以下步骤进行配置: 1. 打开JMeter的安装目录,在`bin/` ... 
- [爬虫]1.2.2 CSS选择器
			CSS (Cascading Style Sheets) 是一种样式表语言,用于描述HTML元素的样式.CSS选择器是CSS规则的一部分,它决定了CSS规则应用于哪些元素.在网络爬虫的开发中,我们经常 ... 
- HTML超文本标记语言1
			一.简介-HTML 1.什么是HTML?? 首先,HTML是WWW的描述语言,由Tim Berners-lee提出. HTML是用于描述网页的一种语言 html是指超文本标记语言(HyperText ... 
- Django创建超级管理员用户
			python manage.py createsuperuser 后面就会提示你输入用户名.邮箱以及密码. 
