最长上升子序列(LIS)简介及其例题分析

一.最长上升子序列(LIS)的相关知识

1.最长上升子序列(Longest  Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。假设我们有一个序列 b i,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。

(或许我们刚开始对于这样的名词感到陌生,对于解释也不理解,那我们就要知道它的前置知识)

 一.什么是子序列?

    一个序列A={a1,a2,...an}中任意删除若干项,剩余的序列叫做A的一个子序列。例如序列A={1,3,5,4,2},删除其中的第3项和第5项,得到序列B={1,3,4},删除其中的第3项和第4项,得到序列C={1,3,2},此时序列B和C是序列A的子序列。

二.什么是最长子序列?

    如果序列中的元素是从小到大排列的,则该序列为上升序列,如果该序列又是其它序列的子序列,则称为上升子序列。例如“1.1 子序列”中提到的B是A的上升子序列,而C是A的子序列,但不是上升子序列。

了解这两个前置知识,那么最长上升子序列就很容易理解了。

即包含元素最多的上升子序列,叫做最长上升子序列。

 

 二.LIS长度的求解方法

一.方法一:动态规划(O(n^2)朴素法)

动态规划的一个特点就是当前解可以由上一个阶段的解推出, 由此,把我们要求的问题简化成一个更小的子问题。我们求最长上升子序列也符合这一特点,我们要求前n个数的最长上升子序列就是可以转换成求前n-1个数的最长上升子序列......这样逐步分解,直到求前1个数的最长上升子序列。

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

其核心代码段为:

for (int i = 1; i <= n; i++) {for (int j = 1; j < i; j++) {if (a[i] > a[j])dp[i] = max(dp[i], dp[j] + 1);}}for (int i = 1; i <= n; i++) {ans = max(ans, dp[i]);}


 

二.方法二:贪心+二分(O(nlogn))

用一个low数组记录长度,low[i]表示长度都为i的LIS结尾元素的最小值,这样我们在记录low的时候,当a[i]大于low[++当前LIS最大长度]时候,直接将a[i]接在low中,否则在low中二分查找大于等于当前元素a[i]的第一个位置pos,用a[i]替换掉之前的low[pos].最后我们找一下最长上升子序列下标满足的解,记录下该子序列即可.(注意,low数组不一定是最长上升子序列,只是长度对等)

这里的二分操作可以用STL中的lower_bound()函数实现。

核心代码段:

low[++sum]=a[1];
for (int i = 2; i <= n; i++) {if (a[i] > low[sum])low[++sum] = a[i];else{int k = lower_bound(low + 1, low + sum + 1, a[i]) - dp;low[k] = a[i];}
}

 

三.例题分析

 一.B3637 最长上升子序列

 

 这一题就相当于最长上升子序列的模版题,通过动态规划(朴素法)就可以解决,这里可以当做模版学习。

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int dp[N], a[N];
int ans, n, m, sum;
int main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];dp[i] = 1;           //初始化,dp都为1,即自身是一个上升子序列}for (int i = 1; i <= n; i++) {for (int j = 1; j < i; j++) {  //如果在之前的序列有小于a[i]的,更新dpif (a[i] > a[j])dp[i] = max(dp[i], dp[j] + 1);}}for (int i = 1; i <= n; i++) {ans = max(ans, dp[i]);   //找出最长的上升子序列}cout << ans << endl;return 0;
}

二.LIS

这一题和刚刚的题目的意思是一模一样的,唯一的区别就是数据范围变大了,变为1e5,如果我们还是和刚刚一样使用O(n^2)的方法,肯定会超时,那么我们就应该使用方法二:贪心+二分       (O(nlogn))

#include<bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], b[N];
int n, m, sum, ans;
int main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}b[++sum] = a[1];     //核心代码段,没什么好说的for (int i = 2; i <= n; i++) {if (a[i] > b[sum])b[++sum] = a[i];else{int k = lower_bound(b + 1, b + sum + 1, a[i]) - b;b[k] = a[i];}}cout << sum << endl;return 0;
}

这里给大家留下两道练习题,这两道题都是在此基础上的变形题,可以会有点难(都是洛谷上的题,可以看题解),后面我也会给出分析。

[ARC149B] Two LIS Sum

P8736 [蓝桥杯 2020 国 B] 游园安排

另外,关于LIS还有一个姊妹叫作LCS(最长公共上上子序列),下次我们将讲解相关内容,好了今天的内容就到这里了。~QVQ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文笔记】Initializing Models with Larger Ones

Abstract 介绍权重选择&#xff0c;一种通过从预训练模型的较大模型中选择权重子集来初始化较小模型的方法。这使得知识从预训练的权重转移到更小的模型。 它还可以与知识蒸馏一起使用。 权重选择提供了一种在资源受限的环境中利用预训练模型力量的新方法&#xff0c;希望能够…

代码随想录Day67 | 695.岛屿的最大面积 1020.飞地的数量

代码随想录Day67 | 695.岛屿的最大面积 1020.飞地的数量 695.岛屿的最大面积1020.飞地的数量 695.岛屿的最大面积 文档讲解&#xff1a;代码随想录 视频讲解&#xff1a; 状态 采用bfs&#xff0c;这道题相较于之前的题变为了求岛屿的最大面积。那就说明我们每遇到一个新的岛屿…

【Linux】软件管理yum | 编辑器vim | vim插件安装

目录 1. Linux软件管理yum 1.1 什么是软件包 1.2 查看软件包 1.3 如何安装软件 1.4 如何卸载软件 2. Linux编辑器vim 2.1 vim的基本概念 2.2 vim的基本操作 2.3 vim正常模式命令集 2.4 vim末行模式命令集 2.5 简单vim配置 2.6 插件安装 1. Vim-Plug 3. coc.nvim …

如何自己系统的学python

学习Python是一项很好的投资&#xff0c;因为它是一种既强大又易于学习的编程语言&#xff0c;适用于多种应用&#xff0c;如数据分析、人工智能、网站开发等。下面是一个系统学习Python的步骤建议&#xff1a; 基础准备 安装Python&#xff1a; 访问Python官网下载最新版本的…

微服务获取当前登录用户信息

一&#xff0c;实现思路 1&#xff0c;基于JWT令牌登陆方式 JWT实现登录的&#xff0c;登录信息就保存在请求头的token中。因此要获取当前登录用户&#xff0c;只要获取请求头&#xff0c;解析其中的token。 1&#xff09;&#xff0c;Gateway网关拦截&#xff0c;解析用户信…

微信小程序-生命周期

页面生命周期 onLoad: 页面加载时触发的方法&#xff0c;在这个方法中可以进行页面初始化的操作&#xff0c;如获取数据、设置页面状态等。 onShow: 页面显示时触发的方法&#xff0c;在用户进入页面或从其他页面返回该页面时会调用此方法。可以在此方法中进行页面数据刷新、动…

Onenote软件新建笔记本时报错:无法在以下位置新建笔记本

报错现象&#xff1a; 当在OneNote软件上&#xff0c;新建笔记本时&#xff1a; 然后&#xff0c;尝试重新登录微软账户&#xff0c;也不行&#xff0c;提示报错&#xff1a; 解决办法&#xff1a; 打开一个新的记事本&#xff0c;复制粘贴以下内容&#xff1a; C:\Users\Adm…

Mysql中的事务

什么是事务&#xff1a; 多条sql语句&#xff0c;要么全部成功&#xff0c;要么全部失败。 事务的特性&#xff1a; 1&#xff1a;原子性(Atomic)&#xff1a; 组成一个事务的多个数据库操作是一个不可分割的原子单元&#xff0c;只有所有操作都成功&#xff0c;整个事务才会…

在Unity中模拟实现手势识别功能

在虚拟现实(VR)和增强现实(AR)的应用开发中&#xff0c;手势识别技术扮演着至关重要的角色&#xff0c;它允许用户以自然的方式与虚拟世界进行交云。然而&#xff0c;并非所有开发者都有条件使用真实的手势识别硬件。本文介绍了如何在Unity中通过模拟的方式实现一个简单的手势识…

【LeetCode】1768_交替合并字符串_C

题目描述 给你两个字符串 word1 和 word2 。请你从 word1 开始&#xff0c;通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长&#xff0c;就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 https://leetcode.cn/problems/merge-strings-al…

C++调用lua函数

C 调用Lua全局变量(普通) lua_getglobal(lua, "width");int width lua_tointeger(lua,-1);lua_pop(lua,1);std::cout << width << std::endl;lua_close(lua); 这几行代码要放到lua_pcall(lua, 0,0,0);之后才可以. C给lua传递变量 lua_pushstring(lua, …

Python 操作 Excel,如何又快又好?

➤数据处理是 Python 的一大应用场景&#xff0c;而 Excel 则是最流行的数据处理软件。因此用 Python 进行数据相关的工作时&#xff0c;难免要和 Excel 打交道。Python处理Excel 常用的系列库有&#xff1a;xlrd、xlwt、xlutils、openpyxl ◈xlrd &#xff0d; 用于读取 Exce…

点云从入门到精通技术详解100篇-基于点云网络和 PSO 优化算法的手势估计(续)

目录 3 深度图像处理及转化 3.1 双目深度摄像原理及深度图的获取 3.1.1 理想化双目深度相机成像

day47_servlet

今日内容 0 复习昨日 1 接收请求 2 处理响应 0 复习昨日 HTTP请求中 请求行 请求方法,请求路径 请求头 页面信息 请求正文 请求的数据 HTTP响应中 响应行 状态码 信息 响应头 页面信息 响应正文 要给浏览器的内容 1 接收请求 浏览器发出请求,经过web.xml映射匹配,找到Servlet…

STL容器之map和set

map和set ​ c98支持的是单参数的隐式类型转换&#xff0c;而c11支持多参数的隐式类型转换&#xff1b; 1.map和set的使用 1.1set ​ set实现key值不允许修改&#xff0c;是将iterator转变成const_iterator&#xff1b;可以对同一个类型typedef成两个不同的自定义标识符。即…

Rocky 9 安装 R-CytoTRACE

官网给出的详细指南&#xff0c;只是可能大家打不开或者懒得去看E文。 第一步&#xff0c;下载CytoTRACE安装包。 wget https://cytotrace.stanford.edu/CytoTRACE_0.3.3.tar.gz 第二步&#xff0c;打开R或者Rstudio-server # 安装依赖包 if (!requireNamespace("Bioc…

在vue中$nextTick 原理及作用

在vue中$nextTick 原理及作用 Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。 nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现&#xff0c;本质是为了利用 Java…

每周AI新闻(2024年第9周)微软与Mistral AI达成合作 | 谷歌发11B基础世界模型 | 传苹果放弃电动汽车制造转向生成式AI

这里是陌小北&#xff0c;一个正在研究硅基生命的碳基生命。正在努力成为写代码的里面背诗最多的&#xff0c;背诗的里面最会写段子的&#xff0c;写段子的里面代码写得最好的…厨子。 每周日解读每周AI大事件。 大厂动向 【1】微软与Mistral AI达成合作 微软官宣与法国生成…

视频云平台——搭建SRS5平台支持GB28181视频流的推送

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

谨用ArrayList中的subList方法

谨用ArrayList中的subList方法 规范一&#xff1a; ArrayList 的 subList 结果不可强转成 ArrayList&#xff0c;否则会抛出 ClassCastException 异常&#xff1a; public static void test7() {List<Integer> list new ArrayList<>();list.add(1);list.add(2);…