最长上升子序列(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]的,更新dp
			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]);   //找出最长的上升子序列
	}
	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~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10.轮廓系数-机器学习模型性能的常用的评估指标

轮廓系数&#xff08;Silhouette Coefficient&#xff09;是评估聚类算法效果的常用指标之一。它结合了聚类的凝聚度&#xff08;Cohesion&#xff09;和分离度&#xff08;Separation&#xff09;&#xff0c;能够量化聚类结果的紧密度和分离度。 背景 1.聚类分析的背景 在…

操作系统(1)——学习导论(Ⅱ)

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/6grrU) 学习导论&#xff08;Ⅱ&#xff09;操作系统-赏前人佳作大型操作系统大型操作系统的一些特点和功能举例 服务器操作系统服务器操作系统特点和功能举例 多处理器操作系统举例 个人计算机操作系统举例 掌上计算机操作…

Jmeter接口测试---随机数、加密、cookie鉴权、断言、CSV参数化

随机数 第一步&#xff1a;选择工具-函数助手对话框 第二步&#xff1a;选择random&#xff0c;设置最大值最小值&#xff0c;复制函数字符串到指定位置 加密接口 类型&#xff1a;AES、DES、Base64、RSA&#xff08;可以解密&#xff09; | MD5、SHA、HmacSHA&#xff08;不…

【Linux系统化学习】线程概念

目录 线程的概念 线程的引出 什么是线程 理解线程比进程更加的轻量化 线程的优点 现成的缺点 线程异常 线程用途 Linux进程VS线程 线程的简单现象 线程的概念 有关操作系统的书籍或者课本都会这样描述线程&#xff1a; 线程是比进程轻量化的一种执行流线程是进程内部…

CogCaliperTool

关于visionpro工具的博客偏少&#xff0c;以下是本人自己查阅visionpro官方文档完成的&#xff08;注意标红的计分函数模式&#xff09;: 本主题介绍Caliper工具&#xff0c;这是一种视觉工具&#xff0c;可在图像的定义明确的区域内提供快速准确的图案检测和定位。 卡尺工具…

GPU 硬件与 CUDA 程序开发工具

GPU 硬件简介 从十多年前起&#xff0c;GPU 的浮点数运算峰值就比同时期的 CPU 高一个量级&#xff1b;GPU 的内存带宽峰值也比同时期的 CPU 高一个量级。 CPU 和 GPU 的显著区别是&#xff1a;一个典型的 CPU 拥有少数几个快速的计算核心&#xff0c;而一个典型的 GPU 拥有几…

考研复试类比社团招新,无所谓“公平”,导师选谁都是他的权力

这篇文章是抖音和b站上上传的同名视频的原文稿件&#xff0c;感兴趣的csdn用户可以关注我的抖音和b站账号&#xff08;GeekPower极客力量&#xff09;。同时这篇文章也为视频观众提供方便&#xff0c;可以更加冷静地分析和思考。文章同时在知乎发表。 我考研一战的时候计算机考…

Linux网络编程—— IO多路复用

Linux网络编程—— IO多路复用 1. I/O 多路复用&#xff08;I/O多路转接&#xff09;1.1 常见的几种I/O模型 2. select3. poll4. epoll :star: 1. I/O 多路复用&#xff08;I/O多路转接&#xff09; I/O 多路复用 使得程序能 同时监听 多个文件描述符&#xff0c;能够提高程序的…

kafka消费者重平衡是什么?怎么避免?

消费者重平衡是指主题下的分区怎么分配给消费者的过程。下面这个图可以看出该过程&#xff1a;原来有2个消费者&#xff0c;3个分区&#xff0c;其中一个消费者肯定就的处理2个分区了。那么当新加入消费者时&#xff0c;则每个消费者就只处理一个分区了。处理这个分区过程的叫协…

【HTML5】浏览器不能显示字体报错Failed to decode downloaded font问题解决

把网上的项目中字体通过链接保存下来在本地上使用&#xff0c;在本地服务器上运行站点发现&#xff0c;用Chrome浏览器访问的时候&#xff0c;出现错误提示不能正常显示字体&#xff0c;怎么解决呢&#xff0c;看看怎么搞。 文章目录 发现问题提示警告提示错误 字体检查打开文件…

分布式ID生成系统之雪花算法详解

在当今的云计算和微服务架构盛行的时代&#xff0c;分布式系统已成为软件开发的重要组成部分。随着系统规模的扩大和业务的复杂化&#xff0c;对数据一致性和唯一性的要求也越来越高&#xff0c;尤其是在全局唯一标识符&#xff08;ID&#xff09;的生成上。因此&#xff0c;分…

【鸿蒙开发】第十五章 ArkTS基础类库-并发

1 简述 并发是指在同一时间段内&#xff0c;能够处理多个任务的能力。为了提升应用的响应速度与帧率&#xff0c;以及防止耗时任务对主线程的干扰&#xff0c;OpenHarmony系统提供了异步并发和多线程并发两种处理策略&#xff0c;ArkTS支持异步并发和多线程并发。并发能力在多…

FRM模型十四:FRA估值

什么是FRA FRA&#xff08;Forward rate agrreement&#xff09;远期利率协议&#xff0c;是一种场外衍生品。FRA在0时刻确定&#xff0c;在未来时刻进行交易的协议。例如FRA3,6表示双方约定在3个月后以Rk的利率水平借款3个月。 应用场景&#xff1a;某公司未来3个月有融资需…

Django官网项目

项目准备 使用VSCODE做IDE。 检查Python版本。 sudo apt install sudo apt update python3 --version创建项目路径&#xff0c;创建虚拟环境&#xff0c;创建项目 路径 \mysite 进入路径&#xff0c;运行VSCODE 运行 "code ." 创建虚拟环境。 选择 >python: c…

CommandLineRunner的使用

背景 在项目启动时需要做一些数据预加载或者某些操作&#xff0c;需要怎么办呢&#xff0c;方法其实有好几种&#xff0c;这里主要讲一下SpringBoot提供的CommandLineRunner接口的使用。一、案例说明以及实现 1.实现CommandLineRunner接口 定义一个类实现CommandLineRunner接…

PyTorch-卷积神经网络

卷积神经网络 基本结构 首先解释一下什么是卷积&#xff0c;这个卷积当然不是数学上的卷积&#xff0c;这里的卷积其实表示的是一个三维的权重&#xff0c;这么解释起来可能不太理解&#xff0c;我们先看看卷积网络的基本结构。 通过上面的图我们清楚地了解到卷积网络和一般网…

剪辑调色软件有哪些 会声会影视频剪辑软件 会声会影和剪映

视频调色做不好&#xff0c;可能不是操作的问题&#xff0c;而是剪辑软件没选对。大师级的画面感&#xff0c;就要用大师级的视频剪辑软件。不用费时费力苦心钻研&#xff0c;也无须死记硬背各种参数的软件&#xff0c;才是真正适合自己的剪辑调色软件。有关剪辑调色软件有哪些…

节省时间,创造价值:人工智能在工作中的实际应用

AI时代的工作流程&#xff1a;智能化操作&#xff0c;创新不止步 在当前的人工智能技术领域&#xff0c;无论是国内研发还是国际上的先进大型模型&#xff0c;本质上均采用了GPT&#xff0c;即生成式预训练Transformer模型。该模型的核心能力在于基于已学习的知识库生成回答。其…

用Java语言创建的Spring Boot项目中,如何传递数组呢??

问题&#xff1a; 用Java语言创建的Spring Boot项目中&#xff0c;如何传递数组呢&#xff1f;&#xff1f; 在这个思路中&#xff0c;其实&#xff0c;Java作为一个后端开发的语言&#xff0c;没必要着重于如何传入&#xff0c;我们主要做的便是对传入的数组数据进行处理即可…

李沐动手学习深度学习——3.3练习

欢迎讨论 1. 如果将小批量的总损失替换为小批量损失的平均值&#xff0c;需要如何更改学习率&#xff1f; 找到相关的函数介绍nn.MSELoss 默认api nn.MSELoss中是小批量损失的平均值&#xff0c;所以学习率为0.03 拿到对应的batch loss细节如下&#xff1a; 当学习率为0.0…