LIS最长上升子序列总结

LIS最长上升子序列详解(动态规划、贪心+二分、树状数组) 1.摘要: 关于LIS部分,本篇博客讲一下LIS的概念定义和理解,以及求LIS的三种方法,分别是O(n^2)的DP,O(nlogn)的二分+贪心法,以及O(nlogn)的树状数组优化的DP,最后附上几道非常经典的LIS的例题及分析。 2.LIS的定义: 最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中... 阅读详情

为了让自己更好的记住学过的知识,我要写博客,将做题中用到的一些方法和一类问题进行总结。

今天做题,碰到了一题关于最长上升子序列的题目,先上题

牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。

输入描述:

输入包括两行,第一行包括一个整数n(1 ≤ n ≤ 10^5),即数列的长度;
第二行n个整数a_i, 表示数列中的每个数(1 ≤ a_i ≤ 10^9),以空格分割。

输出描述:

输出一个整数,表示最长的长度。

输入例子:

6 
7 2 3 1 5 6

输出例子:

5

对于这类笔试题,目前我也只学习了动态规划、双指针、递归、二分、哈希表、单调队列几个基础方法,具体问题具体分析的能力还得多多锻。用了双指针,可惜只有20%的样例通过,之前没做过LIS的题目,今天先总结一下最长子序列问题(LIS),主要也是以LeetCode上的题目展开,让读到这篇文章的人尽可能的将此问题理解的深点。

LeetCode 300. 最长上升子序列

问题描述

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

解决方法
DP动态规划—O(n^2)、二分+贪心法—O(nlogn)、树状数组优化的DP—O(nlogn)

结题思路

最长上升子序列包含的意思

  1. 子序列元素在原数组中的下标是有序的,但不是连续的;
  2. 子序列元素值是上升的。

主要讲一下dp方法,用dp[i]表示以第i个元素结尾的长上升子序列得长度,例如

dp[0]表示[10]的结果是1;

dp[1]表示[10,9]的结果还是1;

dp[2]表示[10,9,5]的结果还是1;

dp[3]表示[10,9,2,5]的结果是2;

dp[4]表示 [10,9,2,5,3]的结果还是2;

dp[5]表示 [10,9,2,5,3,7]的结果是3;

dp[i]的结果与d[0]~dp[i-1]都有关,我们假设0<=j<=i-1;那么我们能够得到

dp状态转移方程:dp[i]=max(dp[i],dp[j]+1);

注意的一点是初始化dp[i]=1;dp的时间复杂度是O(n^2),因此不算最优。

二分+贪心法—O(nlogn)、树状数组优化的DP—O(nlogn)的思路大家可参考LeetCode 300 。

C++代码

#include <iostream>
#include <string>
#include <vector>

using namespace std;
int main()
{
    int n;
    cin>>n;
    
    vector<int> res(n);
    for(int i=0;i<n;i++)         
        cin>>res[i];
    
    int ans=0;
    vector<int> dp(n,1);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<i;j++)  //j代表前res[0]~res[i-1]
        {
            if(res[i]>res[j])  //res[i]>res[j]说明相对于以j结尾的数组的最长子序列又可以增1啦
                dp[i]=max(dp[i],dp[j]+1);   
        }
        ans=max(ans,dp[i]);
    }
    cout<<ans<<endl;
}

LeetCode 128. 最长连续序列

问题描述

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)。

示例:

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

解决方法
利用哈希表unordered_set

结题思路

最长上升子序列包含的意思

  1. 子序列元素在原数组中的下标是无序的;
  2. 子序列元素值是递增加1的。

这题的难点在于规定了时间复杂度为O(n),那么排序肯定是用不上了。

这里主要讲一下用unordered_set方法,LeetCode上用的都是unordered——map<int,int>,感兴趣的可以去查看一下。

解题思路主要是先将数据放到哈希表中。遍历哈希表,对每一个数据左右两边进行查找哈希表,用到了哈希表的count()函数,存在返回>0,反之返回0。知道左右查查找完毕,且每查找到一个数,则都要将其在哈希表中删除。这样才能保证所有的元素只遍历一次,复杂度是O(n)。

C++代码

#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;
int main()
{
    int n;
    cin>>n;

    unordered_set<int> myhash;   //建立哈希表
    int value;
    for(int i=0;i<n;i++)
    {
        cin>>value;
        myhash.insert(value);
    }

    int ans=1;
    for(auto c:myhash)
    {
        int temp=1;
        for(int j=c-1;myhash.count(j);j--)  //向左遍历
        {
            myhash.erase(j);
            temp++;
        }
        for(int j=c+1;myhash.count(j);j++) //向右遍历
        {
            myhash.erase(j);
            temp++;
        }
        //myhash.erase(c); 不能删除自己,会段错误。
        ans=max(ans,temp);
    }
    cout<<ans;
}

LeetCode 845. 数组中的最长山脉

问题描述

我们把数组 A 中符合下列属性的任意连续子数组 B 称为 “山脉”:

  • B.length >= 3

  • 存在 0 < i < B.length - 1 使得 B[0] < B[1] < … B[i-1] < B[i] > B[i+1] > … > B[B.length - 1]

    (注意:B 可以是 A 的任意子数组,包括整个数组 A。)

给出一个整数数组 A,返回最长 “山脉” 的长度。

如果不含有 “山脉” 则返回 0。

示例 1:

输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。

示例 2:

输入:[2,2,2]
输出:0
解释:不含 “山脉”。

提示:

​ 0 <= A.length <= 10000
​ 0 <= A[i] <= 10000

解决方法
利用哈希表unordered_set

结题思路

这题的难度不大,不过是最接近牛牛那题的,算是简单版,难的题目其实也都是从简单的过来的,那么难题的解题方法也是从小的方法合起来解决的,所以多多积累知识点还很重要的。

言归正传,这题的主要解法是用双指针,和上一题有点类似,不过这个不用删除元素。因为约束条件要求山脉的长度>3,那么我们的遍历就从:1<=i<=n-2;

C++代码

#include <iostream>
#include <algorithm>
#include <unordered_set>
#include <vector>
using namespace std;
int main()
{
    int n;
    cin>>n;
    vector<int> res(n);
    for(int i=0;i<n;i++)
        cin>>res[i];

    if ( n< 3)  return 0;

    int ans = 1;
    for (int i = 1; i < res.size() - 1; i++) {
        if (res[i] > res[i - 1] && res[i] > res[i + 1]) {
            int l = i - 1;
            int r = i + 1;
            while (l > 0 && res[l - 1] < res[l]) {
                l--;
            }
            while (r < res.size() - 1 && res[r] > res[r + 1]) {
                r++;
            }
            ans = max(ans, r - l + 1);
        }
    }
    cout<<ans<<endl;

}



这三个题目是LIS问题中比较基础的题目,但是笔试一般不会这么简单,像牛牛这题,就加了一个限制条件—最多只改变一个数,那么这题的解法就变困难些,那么这题该如何解呢?

解题思路

空间换时间,额外建立两个数组,一个left,一个right

left存放得是以第i个元素为结尾点自左向右的最长连续上升子序列(下标连续,值递增)

right存放得是以第i个元素为起始点自左向右的最长连续上升子序列(下标连续,值递增)

以[7 2 3 1 5 6]为例

left[0]=1,right[5]=1

left[1]=1,right[4]=2

left[2]=2,right[3]=3

left[3]=1,right[2]=1

left[4]=2,right[1]=2

left[5]=3,right[0]=1

用的是dp动态规划

状态转移矩阵

​ left[i]=nums[i]>nums[i-1]?left[i-1]+1:1;

​ right[i]=nums[i]<nums[i+1]?right[i+1]+1:1;

然后得到dp[i]=max(left[i]+right[i]-1);

C++代码

#include <iostream>
#include <algorithm>
#include <unordered_set>
#include <vector>
using namespace std;
int main()
{
    int n;
    cin>>n;
    vector<int> res(n);
    for(int i=0;i<n;i++)
        cin>>res[i];

    vector<int> left(n);
    vector<int> right(n);

    left[0]=1;
    for(int i=1;i<n;i++)
        left[i]=res[i]>res[i-1]?left[i-1]+1:1;

    right[n-1]=1;
    for(int i=n-2;i>=0;i--)
        right[i]=res[i]<res[i+1]?right[i+1]+1:1;

    int ans=0;
    for(int i=0;i<n;i++)
    {
        ans=max(right[i],max(left[i],ans));
        if(i>0 && i<n-1 && res[i+1]-res[i-1]>=2)
            ans=max(ans,right[i+1]+left[i-1]+1);
    }
    cout<<ans;
    return ans;
}

以上就是自己对LIS问题的总结,都是一些解决基础问题的方法总结,最近经常用到的方法是动态规划、双指针、哈希表,下次总结一点双指针的问题。

最长上升子序列(LIS)洛谷 题目描述:   传送门 题解思路:和最长公共子序列一样,LIS也是一个经典的dp问题。动规的常见套路是将原问题化简成多个形式相同的子问题。这里求序列的最长上升子序列长度,首先求以ai(ai是序列中的元素,1<=i<=n)结尾的最长上升子序列长度,再从这些以ai结尾的最长子序列长度中选择一个最长的作为整个序列的最长上升子序列长度。 核心算法: 假设maxlen(i)表示以ai为终点的最长上升子序列长度,则有: 初始状态maxlen(1)=1(因为以a1为终点的上升序列就只有a1自己) maxlen 阅读详情

相关推荐

海康视觉平台VisionMaster使用学习笔记(1)

双击图像源设置图像源的属性,像素格式分为Mono8和RDB24分别对应导入的图像是彩色还是黑白。打开相机驱动软件MVS,对连接的相机进行属性上的配置,先对相机的IP进行对应的设置。将自动触发的使能打开,保存配置好的相机属性,默认保存到用户集1中。点击MVS软件中的触发按钮,查看相机是否进行正常的触发拍照。打开VM软件添加一个图像源,选择图像源选项拖出图像源。回到VM软件中将选择相机选项选择到配置好参数的相机。取图方式也可以调整为相机取图,将图像源改为相机。双击相机进行连接后对相机的属性进行配置。

A567852的博客 1万+

最长上升子序列问题总结

看了网上很多关于最长子序列问题的讲解,我是个粗人,太多理论的东西也不爱看,一下是自己的理解(原创); 转载于:https://www.cnblogs.com/wuwangchuxin0924/p/5781567.html...

weixin_33809981的博客 139

反制反心理特征的研究

抓牛股

m0_58032574的博客 908

最长上升子序列(LIS)

LIS:Longest Increasing Subsequence 例题:   单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0&lt;n&lt;20,表示有n个字符串要处理 随后的n行,每行有一个字符串,该字符串的长...

Radium_1209 387

脱壳--02.exe

程序开始 使用OD打开程序 发现无法利用esp定律 程序直接运行 查找模块间调用 随便找到一个函数的调用 发现是FF15方式调用 所以是vs的程序 vs程序大致分成两种 vs20xx (特征函数:GetSystemTimeAsFileTime)和 vc++6.0(特征函数:GetVersion) 通过链接器版本 发现是vc6.0 直接在GetVersion上下断点 重新运行程序 断点断下 返回到调用处 vc6.0和易语言的第一个CALL都是GetVers...

weixin_45012273的博客 1110

LoRa正点原子模块组网步骤

按照我上一篇的博客和视频演示,相信大家一定都可实现了lora模块点对点的通信了。那我们来进行一个比较有高难度的设计吧! 使用多个loRa模块去完成一个组网设计: 在这之前一定要配置模块信息为定点传输 AT+TMODDE要等于1奥 第一步分析通讯协议: 点对点通讯是在透明传输的条件下,地址和信道都是一样的,直接发送接受数据。 组网呢我们利用是: 定向传输就是 A、B的地址、信道不同 假如A是要想B发送信息就用函数来下面: int b[5]...

weixin_43205178的博客 4082

【算法】算法测试题5:牛牛的数列:最长连续子序列

题目描述 链接:https://www.nowcoder.com/ques...来源:牛客网 牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。 输入描述 输入包括两行,第一行包括一个整数n...

weixin_33701251的博客 1758

基于爬虫+词云图+Kmeans聚类+LDA主题分析+社会网络语义分析对大唐不夜城用户评论进行分析

本项目是基于携程网中关于大唐不夜城评论的文本分析,项目中用到了Python爬虫、词频分析、词云图分析、kmeans聚类、LDA主题分析、情感分析、社会网络语义分析等。本次实验我们使用了爬虫、词云图、情感分析、LDA主题分析、TF-IDF+Kmeans、社会网络语义分析等对大唐不夜城的评论进行了分析。关于博文中的源码大家可以关注派森小木屋公众号进入粉丝群领取,如对文章有疑惑,请评论区留言。

m0_64336780的博客 1万+

[编程题]牛牛的数列 【牛客网】【DP】

题目链接 链接: 牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。 解题思路 连续子序列就是子串的意思! 用两个数组endd[]和beginn[]来表示到e[i]这个元素,起始和结束的最长递增子序列的长度 然后枚举断点就好了 #include&...

qq_41925919的博客 1568

PyRoki 入门教程(二)安装与使用

PyRoki是一个用于机器人运动学优化的Python库,具有模块化设计、可扩展性和跨平台支持等特点。它支持逆运动学、轨迹优化和动作重定位等任务,采用Levenberg-Marquardt优化器提高效率。主要功能包括:基于URDF的可微分正向运动学模型、自动生成碰撞基元、通用成本因子和自定义成本函数等。PyRoki支持CPU、GPU和TPU运行,适用于从单机器人到大规模并行处理场景。目前存在一些限制,如仅支持软约束、静态形状和特定关节类型等。官方提供了多个应用示例,包括基础逆运动学、碰撞检测、轨迹优化和手部/

机器人控制与仿真应用 1251

【Flink on k8s】- 1 - Flink Kubernetes Operator 简介 2023

Flink Kubernetes Operator 可以与 Kubernetes 的其他功能和工具集成,可以帮助用户快速定位和解决问题。Flink Kubernetes Operator可以在Kubernetes上实现高可用性,以确保 Flink 集群的稳定性和可靠性。Flink Kubernetes Operator 可以快速地部署 Flink 集群,而无需手动配置和管理集群。Flink Kubernetes Operator可以将Flink集群与其他应用程序隔离,以避免资源争用和干扰。

欢迎来到我的博客,一起探索代码里的世界! 1344

最长单调递增子序列问题 设计一个O(n2)复杂度的算法,找出由n个数组成的序列的最长单调递增子序列

最长单调递增子序列问题 设计一个O(n2)复杂度的算法,找出由n个数组成的序列的最长单调递增子序列 源代码: #include "stdafx.h" #include<stdio.h> int main() { int max = 0, count = 1; int b, c; int a[] = { 2,1,4,7,8,-1,20,-7,-3,-2,1,5 }; int n ...

永远在奔跑的学习者 4882

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

LIS算法: 最长上升子序列

LIS定义 LIS(Longest Increasing Subsequence)最长上升子序列 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。 比如,对于序列(1, 7,

wbin233的博客 2万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

都能看懂的LIS(最长上升子序列)问题

LIS问题介绍: 首先来说一下什么是LIS问题: 有一个长为n的数列a0, a1, ......, a(n-1)。请求出这个序列中最长的上升子序列的长度。上升子序列指的是对于任意的i<j都满足ai<aj的子序列,该问题被称为最长上升子序列(LIS,Longest Increasing Subsequence)的著名问题。 举个栗子:给你一个序列为(1,5 ,2,6,9,1...

ltrbless的博客 4万+

线性DP LIS 最长上升子序列

为:读入a[i],从1到n利用循环记录dp[i],如果当前的a[i]大于a[j],那就意味着a[i]可以加入到以a[j]结尾的子序列中,在这种情况下我们可以更新dp[i]的值,取dp[i]和dp[j]+1的最大值(加1表示在a[j]的基础上添加a[i]至末尾)。:f[i]代表以a[i]为终点的最长上升子序列,g[i]代表以a[i]为起点的最长下降子序列,因为在f[i]和g[i]都计算了一次a[i],所以要减去1,求和-1之后的数量就是以某个元素为转折点的先上升后下降的长度。例如1 2 4 1 3 4。

2301_80170790的博客 1429

LIS最长上升子序列

给定一个数组,让你找出一个最长上升子序列的长度,例如[1,4,6,2,3,5] 答案为4:[1,2,3,5]。 我们用DP[i]表示以下标为i的元素结尾的子序列的最长上升子序列长度 代码如下: ll p[10010]; ll dp[10010]; int main() { ll n, ans = 0; cin >> n; for (int i = 1; i <= n; i++) cin >> p[i]; for (int i =

陈颜的博客 5640

最长上升子序列(LIS)

1LIS的定义: 最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。 2思路: 我们都知道,动态规划的一个特点就是当前解可以由上一个阶段的解推出, 由此,把我们要求的问题简化成一个更小的子问题。子问题具有相同的求解方式,只不过是规模小了而已。最长上升子序列就符合这一特性。我们要求n个...

sherry_zhen的博客 453

LIS-最长上升子序列

LIS(最长上升子序列)是一个经典的问题。首先我们来介绍子序列的概念:子序列指的是一个序列中,按照原顺序选出若干个不一定连续的元素所组成的序列。LIS有两种算法模型:一种是复杂度为的dp模型,另外一种是复杂度为,利用二分实现的模型。

m0_72972329的博客 872

dp——最长上升子序列(LIS)

问题描述 最长上升子序列LIS(longest increasing subsequence):给定一个长度为n的序列 (a1,a2,a3,...,an) a1<a2<a3<...<an 从中选取一个子序列,这个子序列需要单调递增。 问最长上升子序列(LIS)的长度。 eg:1, 5, 2, 4, 11, 7, 9 其中的一些上升子序列为{1,5},{1,...

qq_41972012的博客 264

最长上升子序列(提高LIS之有限制的LIS训练)

目录 题目 解析 朴素LIS lower_bound优化LIS 包含第k个元素的LIS及优化 “二分”求解 从前至后依次求解 题目 题目描述 给出一个长度为N的整数序列,求出包含它的第K个元素的最长上升子序列。 输入 第一行两个整数N, K,第二行N个整数 输出 如题目所说的序列长度。 样例输入 8 6 65 158 170 299 300 155 207 389...

fsy的博客 666

最长上升子序列(LIS)

概述: 关于LIS部分,本篇博客讲一下LIS的概念定义和理解,以及求LIS的三种方法,分别是O(n^2)的DP,O(nlogn)的二分+贪心法,以及O(nlogn)的树状数组优化的DP,最后附上几道非常经典的LIS的例题及分析。 1.动态规划 我们要求n个数的最长上升子序列,可以求前n-1个数的最长上升子序列,再跟第n个数进行判断。求前n-1个数的最长上升子序列,可以通过求前n-2个数的最长上升子序列……直到求前1个数的最长上升子序列,此时LIS当然为1。 让我们举个例子:求 2 7 1 5 6 4 3 8

小飞猪的博客 387

最长上升子序列 (LIS)

1.LIS的定义: 最长上升子序列(longest increasing subsequence),也可以叫最长非降序子序列,简称LIS,不是太难。即一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <...

weixin_30594001的博客 273

LIS(最长上升子序列)

方法一: dp动态规划 状态设计:dp[i]代表以a[i]结尾的LIS的长度  状态转移:dp[i]=max(dp[i], dp[j]+1) (0&lt;=j&lt; i, a[j]&lt; a[i])  时间复杂度:O(N^2)  例题:https://blog.youkuaiyun.com/y201619819/article/details/78354348   方法二:贪心+二分 时间复杂...

雨羊的博客 515

LIS--最长上升子序列

最长上升子序列,又称LIS,是动态规划的一个经典应用。 在原序列取任意多项,不改变它们在原来数列的先后次序,得到的序列称为原序列的子序列。最长上升子序列,就是给定序列的一个最长的、数值从低到高的子序列,最长上升子序列不一定是唯一的。 输入样例: 8 2 1 5 3 6 4 6 3 输出样例: 4 解释:它的最长上升子序列为1,3,4,6和2,3,4,6,长度均为4 ...

qq_41706331的博客 248
下一篇: 08- 10 Smart pointer 智能指针
qq_28126017
博客等级 码龄12年 2粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值