递增子序列

力扣题目链接(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. (jmeter笔记)jmeter监控服务器资源

    jmeter版本:5.2.1 jdk版本:1.8.0_191 监控服务器的CPU/memory.IO.硬盘等信息 1.下载jmeter-plugins-manager-1.4.jar 插件,解压之后把 ...

  2. nginx 工作流程

    NGINX 把http请求处理流程划分为11个阶段,逻辑细分,以模块为单位进行处理.各个阶段可以包含多个http模块,每个阶段以流水线的形式处理请求.这样的分层处理模式与计算机网络的7层模式类似,每个 ...

  3. React整洁的代码的一些原则

    1. Model is everything models are  the heart of your app. If you have models separated from th rest ...

  4. 「SOL」NOI2016 Day1 解题报告

    第一次打 NOI,还是先把以前的 NOI 题刷一遍吧? # 目录 目录 # 目录 # A. 优秀的拆分 excellent # B. 网格 grid # C. 循环之美 cyclic # 小结 # 源 ...

  5. Python 的 Requests 和 Httpx 在爬取应用中的一个区别

    HTTPX是功能齐全的Python3的HTTP客户端,支持同步和异步API,支持HTTP/1.1 和 HTTP/2. 一般情况下,在爬取网页内容的时候,httpx 与 requests 的基本使用方法 ...

  6. HDK_节点开发:SOP_ComputeVisibility

    Houdini版本:18.5.596 节点概述:剔除模型在某视线方向下所有不可见面. 参数界面: 输入:三角化的模型(左),可选输入遮挡模型(右) 原理:在画布上绘制该方向上的最近深度,作为判定各面可 ...

  7. SQL-增删改

    -- 删除表drop table -- 建表create table -- 表注释comment on table ... is ...-- 字段注释comment on column ... is ...

  8. ZSTUOJ刷题⑩:Problem B.--零起点学算法103——查找最大元素

    Problem B: 零起点学算法103--查找最大元素 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 9951  Solved: 4793 Descri ...

  9. Docker之基本原理介绍

    Docker 环境搭建请移步:https://i.cnblogs.com/posts/edit;postId=14090026 First:docker能做什么? 传统的环境部署: 1.环境和项目分开 ...

  10. 一个线程池的c++实现

    前面我们实现了CallBack类,实现了对任意可调用对象的封装,且统一了调用接口. 现在利用CallBack类,我们来实现一个线程池,我们的线程池包含: 1. 状态机, 用于控制和管理线程池的运行.停 ...