题目描述

时间限制: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. web安全之xss跨站脚本攻击

    实验(一) 一.预备知识 1.HTML基础知识 2.phpstudy运用 3.xss的分类   二.实验环境 1.火狐浏览器.Chrome浏览器 2.phpstudy   三.环境搭建 反射型xss环 ...

  2. leetcode日记本

    写在前面: 2019.6开始经过一年的学习,我依然没有学会算法,依然停留在最基本的阶段,面对题目依然一头雾水 但是难不是放弃的理由,根据毛主席的论持久战原理,我决定一天看一点循序渐进,相信总有一天可以 ...

  3. 【入门到精通】❤️「Java工程师全栈知识路线」

    持续更新中- Vue前端开发 章节 内容 实践练习 Vue.js高效前端开发 • (实践练习) 第1章 Vue.js高效前端开发 • [ 一.初识Vue.js ] 第2章 Vue.js高效前端开发 • ...

  4. Java基础周测题,获取用户从控制台输入的年份,判断是否是闰年

    需求说明: 获取用户从控制台输入的年份,判断是否是闰年: 是闰年: 是平年: 实现代码: import java.util.Scanner; public class test { public st ...

  5. SpringBoot 中过滤器的简介及使用方式

    过滤器简介 过滤器依赖Servlet容器,属于Servlet规范的一部分. 在实现上基于Servlet容器的函数回调,可以对几乎所有请求进行过滤. Filter的生命周期由Servlet容器管理. 过 ...

  6. CSS基础 CSS的三大特性以及选择器优先级计算方法

    1.子元素默认会继承父元素的样式,但不是所有的元素都有继承 常见的继承父元素特点的元素有: 1.color 2.font-sytle.font-weight.font-size.font-family ...

  7. CAP原理详解

    转载 https://blog.csdn.net/u013332124/article/details/82874178 文章目录 一.CAP原理介绍 对CAP原理的一些常见的理解误区 二.CAP原理 ...

  8. Linux上天之路(八)之用户和组

    主要内容. 用户创建,删除,修改 密码及密码文件 组创建,删除,修改 组密码及组配置文件 相关文件 Linux用户分类 超级管理员: UID为0 root用户拥有至高无上的命令,root用户不能改名 ...

  9. 使用Crossplane构建专属PaaS体验:Kubernetes,OAM和CoreWorkflows

    关键点:•许多组织的目标是构建自己的云平台,这些平台通常由内部部署架构和云供应商共建完成.•虽然Kubernetes没有提供开箱即用的完整PaaS平台式服务,但其具备完整的API,清晰的技术抽取和易理 ...

  10. Typora 图片上传

    Typora 图片上传 本文借鉴源于:https://zhuanlan.zhihu.com/p/137426939 感谢博主分享 引: 不知道你们平时都在哪里做笔记,本人都是在CSDN Java慈祥 ...