【LeetCode回溯算法#08】递增子序列,巩固回溯算法中的去重问题
递增子序列
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例 1:
输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]示例 2:
输入:nums = [4,4,3,2,1]
输出:[[4,4]]
说明:
- 给定数组的长度不会超过15。
- 数组中的整数范围是 [-100,100]。
- 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况
思路
题目要找出数组的所有递增子序列,所以需要将整个树结构遍历一遍。
根据说明中的第三点,本题也需要去重。
根据示例2可以看出,我们要找的是数组中当前顺序下的递增序列,因此不能对给定数组进行排序
那就恶心了,要知道我们之前在此类问题中去重考的就是 排序后的相邻重复值 + used标记数组
不管没关系,不能排序也行,那就在单层处理时做手脚
这里还是需要使用used数组来记录单层中使用过的元素
在记录遍历值前,需要做以下判断:
- 使用当前遍历值与之前保存在结果数组path中的值进行大小比较(判定是否有递增趋势)
- 判断当前遍历值是否被记录在used数组中(即之前被使用过)
为了实现上述思路,在回溯时不能删除之前used数组记录的值,且used数组改为在单层递归循环前定义,这样每到一层新的递归层时,used数组都会被清空
代码分析
1、确定回溯函数的参数和返回值
参数时题目给的数组nums、beingIndex,这里used数组在回溯函数里面定义
无返回值
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
2、确定终止条件
参考 子集问题 ,如需要收集树结构的所有节点,实际上是不需要返回值的(依靠for循环结束即可)
但是,本题有一个要求是:递增子序列大小至少为2
所以在这里需要单独处理一下这个逻辑(严格来说也不是终止条件)
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 2){//2个以上才保存到结果数组
res.push_back(path);
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
3、确定单层处理逻辑
在单层处理时,还是去循环遍历当前层的元素
不过需要初始化used数组,并且加入当前遍历值与path数组中元素比较大小以及判断当前元素是否被used记录的逻辑
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 1){//2个以上才保存到结果数组
res.push_back(path);
}
//确定单层处理逻辑
//初始化used数组,每次进入递归都会被刷新
int used[201] = {0};//题目中说了,数值范围[-100,100],因此直接用数组就行
for(int i = beginIndex; i < nums.size(); ++i){
//判断逻辑
//path是否为空;当前值是否小于path中最新加入的值;或者当前值是否被记录于used
if(!path.empty() && nums[i] < path.back() || used[100 + nums[i]] == 1){
continue;//满足上述条件就跳过
}
used[100 + nums[i]] = 1;//在nums[i]位置记录出现过当前遍历值
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
}
};
注意点
1、vector::back()
用于取数组最新加入的一个值,这里用来取上次添加的值并与当前遍历值进行比较
2、使用数组来记录数的话,需要创建能够容纳所有元素个数的大小。然后只需在该元素大小位置处标记元素是否出现过即可
例如:如果遍历值是2,那么应该在used数组的100 + 2,也就是下标为102处记录1,表示2出现过1次
加100是因为题目所给范围是[-100,100],前100是负数值
完整代码
class Solution {
private:
//定义结果数组
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数和返回值
void backtracking(vector<int>& nums, int beginIndex){
//(确定终止条件)
//确保递增子序列大小至少为2
if(path.size() > 1){//2个以上才保存到结果数组
res.push_back(path);
}
//确定单层处理逻辑
//初始化used数组,每次进入递归都会被刷新
int used[201] = {0};//题目中说了,数值范围[-100,100],因此直接用数组就行
for(int i = beginIndex; i < nums.size(); ++i){
//判断逻辑
//path是否为空;当前值是否小于path中最新加入的值;或者当前值是否被记录于used
if(!path.empty() && nums[i] < path.back() || used[100 + nums[i]] == 1){
continue;//满足上述条件就跳过
}
used[100 + nums[i]] = 1;//在nums[i]位置记录出现过当前遍历值
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
backtracking(nums, 0);
return res;
}
};
【LeetCode回溯算法#08】递增子序列,巩固回溯算法中的去重问题的更多相关文章
- Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences)
Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences) 深度优先搜索的解题详细介绍,点击 给定一个整型数组, 你的任务是找到所有该数组 ...
- (转载)最长递增子序列 O(NlogN)算法
原博文:传送门 最长递增子序列(Longest Increasing Subsequence) 下面我们简记为 LIS. 定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则 ...
- 最长递增子序列 O(NlogN)算法
转自:点击打开链接 最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS. 排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了. 假设存在一个 ...
- [LeetCode] 491. Increasing Subsequences 递增子序列
Given an integer array, your task is to find all the different possible increasing subsequences of t ...
- Leetcode 673.最长递增子序列的个数
最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[ ...
- nyoj 214-单调递增子序列(二) (演算法,PS:普通的动态规划要超时)
214-单调递增子序列(二) 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:11 submit:35 题目描述: 给定一整型数列{a1,a2..., ...
- Java实现 LeetCode 673 最长递增子序列的个数(递推)
673. 最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, ...
- LIS 最长递增子序列
一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...
- 最长递增子序列(LIS)
最长递增子序列(Longest Increasing Subsequence) ,我们简记为 LIS. 题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6 ...
随机推荐
- Mac10.13-10.15 下玩星际争霸1.16
星际争霸DMG 存储在城通网盘,下载后挂载,复制到 应用程序 里就可以玩了 1, ctfile://xturlDG9QOlg_V29WOwI8UzEKZQdjUWEOOFJ7VCEHYFIxBzlTY ...
- 移动端唤起QQ聊天 (ios android 包含微信、qq内置浏览器)
var u = navigator.userAgent; var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); if(isiOS){ if(u ...
- PHP myadmin 无路径getshell
PHP>5 & MySQl>5 环境:windows下常规的集成环境如 phpstudy,wamp,xampp等. 条件:当已经用弱口令或者爆破登录myadmin以后,没登录进入就 ...
- 2.TS 的数据类型
一.定义变量 TS 中创建变量有四个要素: 定义变量的关键字:var.let.const 变量名 变量的数据类型 变量的初始值 语法结构如下: let 变量名: 数据类型 = 初始值 注意,变量的初始 ...
- python ElementTree 节点标签修改
在网上能找到很多关于xml库ElementTree的增删改查用法,这里我就不重复写那么多了. 主要记录一个,不是很容易查到的用法,比如一个标签,<name></name>,我需 ...
- 逆向学习物联网-网关ESP8266-00课程目的
- B-JUI框架使用探究
附上项目DEMO地址: 点我跳转 下载地址: 点我跳转 先了解一下什么是B-JUI框架: B-JUI(Bootstrap for DWZ)富客户端框架,基于DWZ-jUI富客户端框架修改. 主 ...
- Linux 使用Samba或NFS实现文件共享
SAMBA文件共享服务 Samba是一款开源的文件共享软件,经过简单配置就能够实现Linux系统与Windows系统之间的文件共享工作. 例1:配置Samba服务前,先删掉Samba服务主配置文件中的 ...
- scottrade 手机应用中英文翻译
Dashboard Watch List 自选股 MARKET & NEWS 市场 & 新闻 ALERTS 警告 MONEY MOVEMENT BRANCH LOCAT ...
- Vue3 流程图组件库 Vue Flow 简单使用
官网 Vue Flow 官网 Vue Flow GitHub 安装 npm i --save @vue-flow/core yarn add @vue-flow/core pnpm i @vue-fl ...