递增子序列

力扣题目链接(opens new window)

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是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】递增子序列,巩固回溯算法中的去重问题的更多相关文章

  1. Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences)

    Leetcode之深度优先搜索&回溯专题-491. 递增子序列(Increasing Subsequences) 深度优先搜索的解题详细介绍,点击 给定一个整型数组, 你的任务是找到所有该数组 ...

  2. (转载)最长递增子序列 O(NlogN)算法

    原博文:传送门 最长递增子序列(Longest Increasing Subsequence) 下面我们简记为 LIS. 定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则 ...

  3. 最长递增子序列 O(NlogN)算法

    转自:点击打开链接 最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS. 排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了. 假设存在一个 ...

  4. [LeetCode] 491. Increasing Subsequences 递增子序列

    Given an integer array, your task is to find all the different possible increasing subsequences of t ...

  5. Leetcode 673.最长递增子序列的个数

    最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[ ...

  6. nyoj 214-单调递增子序列(二) (演算法,PS:普通的动态规划要超时)

    214-单调递增子序列(二) 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:11 submit:35 题目描述: 给定一整型数列{a1,a2..., ...

  7. Java实现 LeetCode 673 最长递增子序列的个数(递推)

    673. 最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, ...

  8. LIS 最长递增子序列

    一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...

  9. 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

    关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...

  10. 最长递增子序列(LIS)

    最长递增子序列(Longest Increasing Subsequence) ,我们简记为 LIS. 题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6 ...

随机推荐

  1. C/C++:printf 函数格式化输出,用法详细记录

    printf ( print format )函数是接触C/C++之后接触的第一个函数,它的功能除了输出hello world外,更重要的是进行格式化输出,比如输出整数的%d,输出小数的%f,%lf ...

  2. (jmeter笔记)模拟用户各种场景压测

    插件:standard set 1.jp@gc - Ultimate Thread Group(波浪式压测,最终线程组) Start Threads Count :设置启用并发数 Initial De ...

  3. 查询某数据库的某字段存在于哪些表 mysql

    select column_name,column_comment,data_type ,table_name  from information_schema.columns where table ...

  4. How to Check and Repair EXT4 Filesystem in Linux

    The fsck (stands for File System Consistency Check) is used to check and repair one or more Linux fi ...

  5. 你不知道的JavaScript--作用域

                                                              用简单的代码 展示代码的魅力 1.在浏览器里,在全局范围内,this等价于windo ...

  6. .NET Core使用 Coravel 实现任务调度

    前言 前段时间需要在一个新项目里添加两个后台任务,去定时请求两个供应商的API来同步数据:由于项目本身只是一个很小的服务,不太希望引入太重的框架,同时也没持久化要求:于是我开始寻找在Quartz.Ne ...

  7. hdu4585 Treap与名次树/STL map(C/C++)

    hdu4585 题目地址:https://acm.dingbacode.com/showproblem.php?pid=4585 Shaolin Time Limit: 3000/1000 MS (J ...

  8. Date 对象 定时器

    日期对象 Date 概述:date是表示日期时间的对象,主要的方法是获取时间和设置日期时间. date声明 使用new Date声明 有4种方式 1.不设参数 是获取当前的本地时间 var date ...

  9. input设置自定义属性,并获取值。

    HTML代码: JavaScript代码: 因为busCode不是input标签原生的属性,所以不能使用"点"操作. 非标准属性,要用:obj.getAttribute(" ...

  10. C# 类库 dll 读取配置文件信息

    一:给 C# 类库 dll 添加配置文件并读取配置信息 效果: 1.给类库程序添加配置文件,并命名为:类库名.DLL.config 如上面效果图,类库为:API.dll ,那么其对应的类库配置文件为: ...