题目描述

时间限制:1.0s 内存限制:256.0MB

问题描述

   给定一个长为\(n\)的序列,求它的最长上升子序列的长度。

输入格式

   输入第一行包含一个整数\(n\)。

   第二行包含\(n\)个整数\(a_1,a_2,…,a_n\),为给定的序列。

输出格式

   输出一个非负整数,表示最长上升子序列的长度。

样例输入

 5
1 3 2 5 4

样例输出

 3

数据规模和约定

   \(0<n\leq10^5\),每个数不超过\(10^6\)。

解析

   所谓最长上升子序列,就是给定一列数,求序列中严格上升的子序列,子序列中数的位置不一定连续。

1.动态规划dp

   这是动态规划中的一个经典应用题目,动态规划的思想就是把问题分解为一些本质上还是相同问题的小问题,这些小问题的区别仅在于输入的参数不同,而每一个小问题的解都可以由比他参数更小的一些小问题的解推出,最小的小问题有显而易见的解,这被称之为边界。最长上升子序列(LIS)问题也是这样。

   \(a_i\)(\(1\leq i<n\))表示序列中第\(i\)个整数

   \(dp_i\) 表示以\(a_i\)为结尾的最长上升子序列的长度

   于是,\(dp_i\)要把\(a_i\)加到以\(a_j\)(\(1\leq j<i\))为上升子序列末尾的后面,并且符合\(a_j<a_i\),找一个最大的dp[j],然后令\(dp_i = dp_j + 1\)即求出了\(dp_i\)。

   最后在所有的\(dp_i\)中取一个最大的即为整个序列的最长上升子序列的长度。

   算法时间复杂度为\(O(n^2)\),当范围大一些的时候是有些低效的。

#include <iostream>
#include <algorithm>
using namespace std;
int a[100005], d[100006];
const int INF = 0x3f3f3f3f;
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
int maxx = -INF;
for (int i = 1; i <= n; i++) {
d[i] = 1;
for (int j = 1; j < i; j++)
if (a[j] < a[i])
d[i] = max(d[i], d[j] + 1);
maxx = max(maxx, d[i]);
}
cout << maxx << endl;
return 0;
}
2.二分搜索优化

   \(a_i\)(\(1\leq i<n\))表示序列中第\(i\)个整数

   \(dp_m\) 表示长度为\(m\)的最长公共子序列的末尾最小值

   当\(i=1\)时,\(dp_i=a_i\)。

   当\(i\)逐渐增加,每次扫过\(a_i\),因为\(dp_m\)代表长度为i的最长上升子序列的最小末尾,这可以代表一个长度为m的最长上升子序列,我们考虑可以把\(a_i\)加到哪个最长上升子序列后面构成一个长度\(+1\)的新的最长上升子序列。那么我们就可以在\(dp\)数组中寻找到\(j\)(\(1\leq j\leq m\))并且\(dp_j<a_i\leq dp_{j+1}\),把\(a_i\)加到这个数代表的序列后面:\(dp_{j+1}=a_i\)。

   因为\(dp\)数组是有序的,所以在进行寻找的时候就可以用二分搜索来进行。而当我们把\(a\)数组全部扫描完之后,\(dp\)数组中的最后一个有效的数字的位置即是我们所求的最长上升子序列的长度\(m\)。

   由于循环中的搜索变成了二分搜索,时间复杂度为\(O(log_n)\),所以整体时间复杂度是\(O(nlogn)\)。

#include <iostream>
#include <algorithm>
using namespace std;
int dp[100005], a[100005];
int b_search(int x, int l, int r) {
while (l < r) {
int mid = (r + l) / 2;
if (dp[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main(int argc, char** argv) {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[i] = 0x3f3f3f3f;
}
int m = 1;
dp[1] = a[1];
for (int i = 2; i <= n; i++) {
if (a[i] > dp[m]) dp[++m] = a[i];
else {
int j = b_search(a[i], 1, m);
dp[j] = min(dp[j], a[i]);
}
}
cout << m << endl;
return 0;
}

   在第二个算法中我们可以通过在二分查找中改变“上确界”和“下确界”,以及在第一个算法中通过改变符号(“<”和“<=”或“>”、“>=”等),求出最长不下降、不上升、严格下降子序列等问题。

最长公共子序列-LIS的更多相关文章

  1. 最长公共子序列(LCS)和最长递增子序列(LIS)的求解

    一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...

  2. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

  3. 最长递增子序列(lis)最长公共子序列(lcs) 最长公共上升子序列(lics)

    lis: 复杂度nlgn #include<iostream> #include<cstdio> using namespace std; ],lis[],res=; int ...

  4. 最长公共子序列-LCS问题 (LCS与LIS在特殊条件下的转换) [洛谷1439]

    题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出 一个数,即最长公共子序列的长度 输入样例 5 ...

  5. 最长上升子序列(LIS)与最长公共子序列(LCS)

    1.LIS : 给定一个序列,求它的最长上升子序列(n<=2000) 第一种 O(n^2): dp[i] 为以i为开头的最长上升子序列长度 code1: #include<cstdio&g ...

  6. 最长连续公共子序列(LCS)与最长递增公共子序列(LIS)

    最长公共子序列(不连续) 实际问题中也有比较多的应用,比如,论文查重这种,就是很实际的一个使用方面. 这个应该是最常见的一种了,不再赘述,直接按照转移方程来进行: 按最普通的方式就是,直接构造二维矩阵 ...

  7. 最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

    最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字 ...

  8. 【线型DP模板】最上上升子序列(LIS),最长公共子序列(LCS),最长公共上升子序列(LCIS)

    BEGIN LIS: 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序 ...

  9. 【LCS,LIS】最长公共子序列、单调递增最长子序列

    单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4   输入 ...

随机推荐

  1. 破解C#反编译软件Reflector 11.1.0.2167(最新版)(附补丁下载)

    本文为原创作品,转载请注明出处,作者:Chris.xisaer E-mail:69920579@qq.com QQ群3244694 补丁下载地址:https://download.csdn.net/d ...

  2. 为什么别人的 WordPress 网站那么快?

    越来越多的人使用 WordPress 来搭建网站了,W3techs 最新数据统计显示[1],截止到2021年11月3日,全网有43.0%的网站都是基于WordPress 搭建的.那么问题来了,为什么别 ...

  3. 【机器学*】k*邻算法-03

    心得体会: 需要思考如何将现实对象转化为特征向量,设置特征向量时记住鸭子定律1 鸭子定律1 如果走路像鸭子.说话像鸭子.长得像鸭子.啄食也像鸭子,那它肯定就是一只鸭子 事物的外在特征就是事物本质的表现 ...

  4. [JNI开发]使用javah命令生成.h的头文件

    第一步:进入对应的.java目录 javac xxx.java 生成对应的xxx.class文件 第二步:退回到/java目录 javah -classpath . -jni 包名.类名

  5. Rainbond 对接 Istio 原理讲解和代码实现分析

    一.背景 现有的 ServiceMesh 框架有很多,如 Istio.linkerd等.对于用户而言,在测试环境下,需要达到的效果是快.开箱即用.但在生产环境下,可能又有熔断.延时注入等需求.那么单一 ...

  6. mongdb分片

    实验环境 主机              IP                虚拟通道 centos1       192.168.3.10         vmnet8 centos2       ...

  7. python 面向对象:封装---对象的属性可以是另一个类创建的对象

    # 对象封装:对象的属性可以是另一个类创建的对象 # 案例需求: # 1.士兵许三多有一把AK47 # 2.士兵用枪射击标靶 # 3.枪能装填和发射子弹 class Gun: # 分析: # 枪的属性 ...

  8. Python_获取全部异常信息

    import traceback try: os.getcwd('exc') except Exception: exc = traceback.format_exc() print(exc)

  9. Mysql字符串字段判断是否包含某个字符串的方法

    方法一:like SELECT * FROM 表名 WHERE 字段名 like "%字符%"; 方法二:find_in_set() 利用mysql 字符串函数 find_in_s ...

  10. 微信小程序自定义导航栏组件

    1.首先,要在json文件中设置为自定义的形式 "navigationStyle": "custom" 2.计算相关值 导航栏分为状态栏和标题栏,只要能算出每台 ...