最长上升子序列优化

article/2025/9/20 17:38:13

引言

上次我们说了基础的最长上升子序列(看这一篇前可以先看一下最长上升子序列)

这次,我们再说一下如何优化,提高效率

我们先来看一道模板题

题目:

题目描述

输入格式

输出格式

输入样例

3
1 3 2

输出样例

1

数据范围

想法

应该很容易想到把问题转化为求最大上升子序列,因为这道题是说修改多少个就能变成严格单调递增,其实就是问这个数列中最大上升子序列,除这一个序列外的就是要修改的数字

最原始的代码如下

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;long long a[100001];
int f[100001];
//f[i]表示以第i项结尾的最长上升子序列
int main()
{int n;cin >> n;for(int i = 1;i <= n;i++){cin >> a[i];}int maxn = 0;for(int i = 1;i <= n;i++){f[i] = 1;//初值for(int j = 1;j <= i - 1;j++){if(a[j] < a[i])f[i] = max(f[i],f[j] + 1);maxn = max(maxn,f[i]);}}cout << n - maxn;return 0;
}

 (如果没有看懂上面这段代码的话建议看一下我的上一篇题解)

如果只这样写的话,会有一个样例错了

想要得到满分,则必须进行优化,下面,我们来详细讲一下最长上升子序列的优化

优化

我们来模拟一下基础版本 

上图是原先数组,现在我们要求F[10](以第10项为结尾(就是7)的最大上升子序列长度)

如上图,很多项都能推第10项

但这样的话会很慢,因为每一项都会有这么多项可以推,枚举起来效率实在低,那怎样才能减少要枚举的次数呢?

其实在这几项中有许多没有枚举意义的项就拿第一项(3),第五项(2),第六项(3)举例

 

这三项中,F数组值都是1,就是说以它们为结尾的最长上升子序列长度都是1,那么对于第十项(7)我们只选择有最优的。很容易看出来,第五项(2)才是最优的,因为在这三项中,2是数值最小的不管怎么样,都比第一项和第六项(3)强(因为是要得到最长“上升”子序列,当然是前面数越小对后面越好啊),所以对于F数组值为1的,我们只选择2。

那么,我们把这个操作推广,就会得到:对于F数组值相同的几项中我们选择数值最小的,其他的全部忽略。

所以现在需要一个数组g来存储这些“有用”的项。

假设我们已经有数组g了:

(已经按F数组值从小到大排好了)

现在我们就是要找到这四个数中两边数值刚好能“夹住”7的位置

long long a[100001];
int f[100001];
//f[i]表示以第i项结尾的最长上升子序列
int g[100001];
//g[i]表示上升子序列长度为i时,结尾最小值
int sz = 0;//前i-1个最长有多长
int maxn = 0;for(int i = 1;i <= n;i++){int pos = 1;while(pos <= sz && g[pos] < a[i]) pos++;f[i] = pos;g[pos] = a[i];sz = max(sz,pos);maxn = max(maxn,f[i]);}

在代码中,我们用一个pos来实现:首先pos=1初始化,接下来那个while来循环找到位置

循环条件:pos要在这个这个g数组中的某一个位置(就是其中的就是长度要小于等于最大长度,因为g数组也就只有这些数值了)并且还需要有g数组中的第pos个要小于当前这个数a[ i ]

那循环完后就找到pos了,直接将F[ i ]赋值为pos(注意,不是pos+1,因为在循环中,pos最后会多加一个1),那么我们现在要做的就是改变g[pos]

举刚才那个例子就是说把9划掉,换成7,因为7和9的F数组值相同,最小的必定要好

sz = max(sz,pos);

 对于这行代码:

因为pos有可能比sz大,(循环中不停+1嘛)所以sz值也就要更新了,如果pos大于sz的话那么就sz=pos赋值,所以就是这行代码。

最后我把最终代码附上来

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;long long a[100001];
int f[100001];
//f[i]表示以第i项结尾的最长上升子序列
int g[100001];
//g[i]表示上升子序列长度为i时,结尾最小值
int sz = 0;//前i-1个最长有多长
int main()
{int n;cin >> n;for(int i = 1;i <= n;i++){cin >> a[i];}int maxn = 0;for(int i = 1;i <= n;i++){int pos = 1;//表示以第i项为结尾的最长上升子序列的长度while(pos <= sz && g[pos] < a[i]) pos++;//找到posf[i] = pos;赋值g[pos] = a[i];//既然刚才循环的倒数第二次g[pos]最后一次<a[i],所以这时的g[pos]应该是a[i]sz = max(sz,pos);//更新最大长度,pos有可能大于sz,则sz不是最大长度maxn = max(maxn,f[i]);}cout << n - maxn;return 0;
}


http://chatgpt.dhexx.cn/article/uf0lYG0I.shtml

相关文章

最长上升子序列(LIS)算法

LIS定义 LIS&#xff08;Longest Increasing Subsequence&#xff09;最长上升子序列 一个数的序列bi&#xff0c;当b1 < b2 < … < bS的时候&#xff0c;我们称这个序列是上升的。 对于给定的一个序列(a1, a2, …, aN)&#xff0c;我们可以得到一些上升的子序列(a…

11.最长上升子序列(LIS)

视频讲解&#xff1a;最长上升子序列_哔哩哔哩_bilibili 解题思路&#xff1a; 1.最长上升子序列的含义是从给定的数中选取尽量多的数字形成单调递增的序列 2.可以把以每一个数字形成单调结尾的方案数看待成一个子问题&#xff0c;然后对后面的子问题提供最优解 3.设定状态…

C++动态规划之最长上升子序列

1 子序列与上升子序列 1.1 子序列 一个序列A{a1,a2,...an}中任意删除若干项&#xff0c;剩余的序列叫做A的一个子序列。例如序列A{1,3,5,4,2}&#xff0c;删除其中的第3项和第5项&#xff0c;得到序列B{1,3,4}&#xff0c;删除其中的第3项和第4项&#xff0c;得到序列C{1&#…

最长上升子序列(c++图文详解)

这题思路是这样&#xff0c;假设这个序列长度为n&#xff0c;存在数组a中&#xff0c;maxlen[i]表示以第i个数为终点的最长上升子序列的长度&#xff0c;它被初始化为1&#xff0c;因为一开始单个字符的最长上升子序列都是1&#xff08;它自己&#xff09;&#xff0c;我们先用…

最长上升子序列(动态规划)

子序列 所谓的子序列就是在原来序列中找出一部分组成的序列。 与子段不同&#xff0c;不需要连续的某一段&#xff0c;但是要保持原序列的先后顺序 最长上升子序列 在子序列的基础上&#xff0c;后一项大于前一项。 【题目描述】 【输入格式】 【输出格式】 【输入样例】 1…

最长上升子序列 (LIS) 详解+例题模板 (全)

欢迎访问https://blog.csdn.net/lxt_Lucia&#xff5e;&#xff5e; 宇宙第一小仙女\(^o^)/&#xff5e;萌量爆表求带飞≡Σ((( つ^o^)つ~ dalao们点个关注呗&#xff5e; --------------------------------我只是一条可爱哒分界线------------------------------- 1.摘要&…

Import Dependency Management with Exclusion

文章来源: Import Dependency Management with Exclusion Exclusion at import won’t work, try excluding it from the actual user of the dependency 意思是&#xff1a; 在dependencyManagement里面的dependency中&#xff0c;使用exclusions&#xff0c;是不会有作用的…

maven配置中的 scope, type,optional, classifier, 传递依赖,exclusions解释

scope用于依赖范围控制,它管理哪些依赖在哪些classpath 中可用&#xff0c;哪些依赖包含在一个应用中. 它的取值列表如下: 关于为什么使用provided 引入 servlet-api,jsp-api的问题的澄清: 在eclispe里创建web项目时&#xff0c;eclipse为我们自动添加了这两个jar包&#xff0…

记录--对于$off,Exclude 和 Extract的一点理解

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 一.typescript 高阶类型 Exclude 和 Extract Exclude<T, U> TypeScript 2.8 中增加了 Exclude 类型&#xff0c;该如何理解这个高级类型的定义呢&#xff1f; type Exclude<T, U> T exte…

[1120]Maven依赖冲突解决之exclusions

1. 背景 1、作为java生态下开发者&#xff0c;往往需要使用大量线程的第三方库&#xff0c;一般都是以jar包形式存在。 2、maven作为事实上主流的jar包依赖管理工具&#xff0c;Idea和Eclipse都支持创建maven工程来管理jar包依赖。 3、使用maven进行jar包依赖管理时&#xff0…

logical exclusive 与 physical exclusive 的区别

数字电路中一般会有多个clock&#xff0c;这些clock 相互之间有些是同步的&#xff0c;需要做 timing check 的&#xff0c;有些是异步的&#xff0c;不需要做 timing check 的&#xff0c;还有些是互斥的&#xff0c;需要 exclude 掉的&#xff0c;这些关系就需要在 sdc 中声明…

Maven中 排除依赖 exclusions

使用maven进行jar包依赖管理时&#xff0c;maven会自行管理jar包及其依赖链条&#xff0c;但往往会遇到依赖冲突问题&#xff0c;这时候就可以尝试使用exclusions来进行依赖管理 demo:排除tomcat 启用 jetty <dependency><groupId>org.springframework.boot</g…

Exclusive or

题目连接 题意&#xff1a; 每次给一个n&#xff0c;求 (2≤n<10500) 分析&#xff1a; 先说一下自己的想法&#xff0c;如果将n换成二进制数&#xff0c;也就一两千位左右&#xff0c;那么一位一位处理是可以接受的。将0-n写成二进制形式后&#xff0c;显然所有数某一个二进…

Maven依赖冲突解决之exclusions

Maven依赖冲突解决之exclusions 1. 背景 作为java生态下开发者,往往需要使用大量线程的第三方库,一般都是以jar包形式存在。maven作为事实上主流的jar包依赖管理工具,Idea和Eclipse都支持创建maven工程来管理jar包依赖。使用maven进行jar包依赖管理时,maven会自行管理jar包…

【带你吃透C++】引用详解(引用和指针的区别)

引用 1 引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称"…

浅析C++中引用与指针的区别

引用和指针的概念及区别 1. 引用及指针概念1.1 指针概念1.2 引用概念 2. 引用与指针的区别 1. 引用及指针概念 如果熟悉指针和引用的使用&#xff0c;应该能感觉到指针和引用在很多场景使用起来还是有很大的相似性的&#xff0c;尽管它们在语法层面上是俩个完全不同的概念。 那…

C语言-引用和指针的区别?

①引用的格式&#xff1a;数据类型 &引用名 变量名&#xff1b; 指针的格式&#xff1a;数据类型 *变量名指向的变量地址&#xff1b;②使用引用一定要进行初始化 指针为了不出现野指针&#xff0c;也要进行初始化为NULL ③引用只能对数组的元素使用&#xff0c;不能对整个…

c++引用与指针的区别

目录 一、从语法上来讲 二、从汇编层面来看 一、从语法上来讲 1.指针是存储某个实例的地址&#xff0c;引用是实例的别名 2.程序为指针分配内存区域&#xff0c;而不为引用分配内存区域 3.指针使用时要加 “ * ”&#xff0c;解引用&#xff0c;引用可以直接使用 例&…

C++引用和指针的区别

作者&#xff1a;RainMan 链接&#xff1a;https://www.zhihu.com/question/37608201/answer/545635054 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 引用是C引入的重要机制&#xff08;C语言没有引用&#xff0…

引用和指针的区别

引用和指针的区别: C的引用(Reference) 1.定义引用就是给某个变量起别名&#xff0c;对引用的操作和对该变量操作完全相同。 int a 10&#xff1b; int& b a;//b就是a的别名 b; cout << a << endl;//11 2 常引用 1&#xff09;定义引用时加const修饰&#…