摘要

本文主要介绍了 经典算法题 最长上升子序列的动态规划解法,同时用北大OJ的案例来补充说明,意在学习动态规划的基本思想和解题过程,供大家一起学习!


什么是最长上升子序列?

最长上升子序列(Longest  Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。假设我们有一个序列 b i,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们也可以从中得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N,但必须按照从前到后的顺序。比如,对于序列(1, 7, 3, 5, 9, 4, 8),我们就会得到一些上升的子序列,如(1, 7, 9), (3, 4, 8), (1, 3, 5, 8)等等,而这些子序列中最长的(如子序列(1, 3, 5, 8) ),它的长度为4,因此该序列的最长上升子序列长度为4。

是不是觉得好抽象~没事我给你解释~

首先需要知道,子串子序列的概念,我们以字符子串和字符子序列为例,更为形象,也能顺带着理解字符的子串和子序列:

(1)字符子串指的是字符串中连续的n个字符,如abcdefg中,ab,cde,fg等都属于它的字串。

(2)字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序。如abcdefg中,acdg,bdf属于它的子序列,而bac,dbfg则不是,因为它们与字符串的字符顺序不一致。

知道了这个,数值的子序列就很好明白了,即用数组成的子序列。这样的话,最长上升子序列也很容易明白了,归根结底还是子序列,然后子序列中,按照上升顺序排列的最长的就是我们最长上升子序列了,这样听来是不是就很容易明白啦~

还有一个非常重要的问题:请大家用集合的观点来理解这些概念,子序列、公共子序列以及最长公共子序列都不唯一,但很显然,对于固定的数组,虽然LIS序列不一定唯一,但LIS的长度是唯一的。再拿我们刚刚举的栗子来讲,给出序列 ( 1, 7, 3, 5, 9, 4, 8),易得最长上升子序列长度为4,这是确定的,但序列可以为 ( 1, 3, 5, 8 ), 也可以为 ( 1, 3, 5, 9 )。


好了,知道什么是最长上升子序列之后,我们来看看怎么求长度。

LIS的解法有好几种,例如O(n^2)的DP,O(nlogn)的二分+贪心法,以及O(nlogn)的树状数组优化的DP。

在这里我详细介绍第一种,动态规划的解法。

动态规划解法

我们都知道,动态规划的一个特点就是当前解可以由上一个阶段的解推出, 由此,把我们要求的问题简化成一个更小的子问题。子问题具有相同的求解方式,只不过是规模小了而已。最长上升子序列就符合这一特性。我们要求n个数的最长上升子序列,可以求前n-1个数的最长上升子序列,再跟第n个数进行判断。求前n-1个数的最长上升子序列,可以通过求前n-2个数的最长上升子序列……直到求前1个数的最长上升子序列,此时LIS当然为1。

  让我们举个例子:求 2 7 1 5 6 4 3 8 9 的最长上升子序列。我们定义d(i) (i∈[1,n])来表示前i个数以A[i]结尾的最长上升子序列长度。

  前1个数 d(1)=1 子序列为2;

  前2个数 7前面有2小于7 d(2)=d(1)+1=2 子序列为2 7

  前3个数 在1前面没有比1更小的,1自身组成长度为1的子序列 d(3)=1 子序列为1

  前4个数 5前面有2小于5 d(4)=d(1)+1=2 子序列为2 5

  前5个数 6前面有2 5小于6 d(5)=d(4)+1=3 子序列为2 5 6

  前6个数 4前面有2小于4 d(6)=d(1)+1=2 子序列为2 4

  前7个数 3前面有2小于3 d(3)=d(1)+1=2 子序列为2 3

  前8个数 8前面有2 5 6小于8 d(8)=d(5)+1=4 子序列为2 5 6 8

  前9个数 9前面有2 5 6 8小于9 d(9)=d(8)+1=5 子序列为2 5 6 8 9

  d(i)=max{d(1),d(2),……,d(i)} 我们可以看出这9个数的LIS为d(9)=5

  总结一下,d(i)就是找以A[i]结尾的,在A[i]之前的最长上升子序列+1,当A[i]之前没有比A[i]更小的数时,d(i)=1。所有的d(i)里面最大的那个就是最长上升子序列。

状态设计:F [ i ] 代表以 A [ i ] 结尾的 LIS 的长度

状态转移:F [ i ] = max { F [ j ] + 1 ,F [ i ] } (1 <= j <  i,A[ j ] < A[ i ])

边界处理:F [ i ] = 1 (1 <= i <= n)

时间复杂度:O (n^2)


具体例子

这里我们以 北大OJ (POJ 2533)最长上升子序列 为例子

描述

ai的数字序列如果a1 < a2 <…<一个。设给定数字序列(a1, a2,…)的子序列, aN)为任意序列(ai1, ai2,…, 1 <= i1 <= i2 <…< iK <= n。例如,序列(1,7,3,5,9,4,8)已经排序了子序列,如(1,7),(3,4,8)等。所有最长有序子序列的长度都是4,例如(1,3,5,8)。

当给定数字序列时,程序必须找到最长有序子序列的长度。

输入

输入文件的第一行包含序列N的长度。第二行包含序列的元素—N个整数,每个整数的范围是0 ~ 10000,用空格隔开。1 <= n <= 1000

输出

输出文件必须包含单个整数-给定序列的最长有序子序列的长度。

样例输入

7
1 7 3 5 9 4 8

样例输出

4

 实现代码:

#include<iostream>
#include<math.h>
#include<algorithm>
#include<string>
using namespace std;
int b[1010]; //输入的数据
int maxlen[1010]; //记录以第i个位终点的最长上升子序列长度
int main(){int n;scanf("%d",&n);for(int i=0;i<n;i++)scanf("%d",&b[i]);maxlen[0]=1; //第一个显然是1//从第二个数开始 依次求for(int i=1;i<n;i++){int temp=0; //记录长度的,每求一个数就清零for(int j=0;j<i;j++){if(b[j]<b[i]){if(temp < maxlen[j])temp = maxlen[j];}}//退出循环后找到之前的最长序列maxlen[i] = temp + 1;}//从头到尾遍历,找最大值int maxl=-1;for(int i=0;i<n;i++)if(maxl<maxlen[i])maxl=maxlen[i];printf("%d\n",maxl);return 0;
}

~~~如果觉得这篇文章对你有帮助的话,还请点个赞或是留言,谢谢呀

动态规划—最长上升子序列(POJ 1458)相关推荐

  1. 动态规划—最长公共子序列问题 HDU-1159 Common Subsequence

    动态规划-最长公共子序列问题 Common Subsequence [ HDU - 1159 ] A subsequence of a given sequence is the given sequ ...

  2. 详解动态规划最长公共子序列--JavaScript实现

    前面两篇我们讲解了01背包问题和最少硬币找零问题.这篇将介绍另一个经典的动态规划问题--最长公共子序列.如果没看过前两篇,可点击下面链接. 详解动态规划最少硬币找零问题--JavaScript实现 详 ...

  3. 动态规划1--最长公共子序列

    动态规划1--最长公共子序列 一.动态规划 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并 综合子问题的解导出大问题的解的方法,问题求解耗时 ...

  4. 动态规划——最长上升子序列问题(LIS)

    动态规划--最长上升子序列问题(LIS) 最长上升子序列问题(LIS).给定n个整数A1,A2,-,AnA_1, A_2, \dots , A_n,按从左到右的顺序选出尽量多的整数,组成一个上升子序列 ...

  5. 最长公共子序列php,动态规划(最长公共子序列LCS)

    概念 求解决策过程最优化的结果 (可能有多个) 把多阶段过程转化为一系列单阶段过程,利用各阶段之间的关系,逐个求解 计算过程中会把结果都记录下,最终结果在记录中找到. 举例 求两个字符串的最长公共子序 ...

  6. 最长公共子序列动态规划c语言,动态规划----最长公共子序列(C++实现)

    最长公共子序列 题目描述:给定两个字符串s1 s2 - sn和t1 t2 - tm .求出这两个字符串的最长公共子序列的长度.字符串s1 s2 - sn的子序列指可以表示为 - { i1 < i ...

  7. OpenJudge 2757 最长上升子序列 / Poj 2533 Longest Ordered Subsequence

    1.链接地址: http://poj.org/problem?id=2533 http://bailian.openjudge.cn/practice/2757 2.题目: 总Time Limit: ...

  8. 动态规划--最长公共子序列

    1. 子序列 摘自维基百科 在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置而形成的新序列. 例如: 令 为一序列 那么,以下序列 是 的子序列之一.对应定义里的自然数 ...

  9. 动态规划——最长公共子序列(LCS)

    最长公共子序列的问题描述为: 下面介绍动态规划的做法. 令 dp[i][j] 表示字符串 A 的 i 号位与字符串 B 的 j 号位之前的 LCS 长度(下标从 1 开始),如 dp[4][5] 表示 ...

最新文章

  1. 软考总结——虚存管理
  2. shell版俄罗斯方块
  3. 【管理心得之一】不要用“可有可无”的事,挑战他人对这件事的原则和底线...
  4. 每个人眼中都有一个哈姆雷特
  5. ThreadPoolExecutor源码解析(一)
  6. 百度搜索,你画了好大一张饼,你还打算欺骗多少人呢?有图为证
  7. OpenGL 三角形的渲染
  8. [LOJ500]ZQC的拼图
  9. python selenium p_python selenium 常见问题列表
  10. 多线程 调用多线程的方法 Runtime与ProcessBuilder
  11. 2010上半年网络工程师上午试题分析与解答
  12. php yii框架连接数据库,Yii 框架使用数据库(databases)的方法示例
  13. img元素srcset属性浅析
  14. pdf pmp书籍第六版_PMP项目管理知识体系指南PMBOK第六版高清中文版PDF下载.pdf
  15. Zcurd与Eova对比,欢迎吐槽!
  16. 腾讯云海外音视频技术架构 — 挑战和优化
  17. JAVA中成员变量和局部变量区别
  18. 小程序调试技术详解(基于小猴小程序)
  19. 联通速品简易测试报告
  20. Vue.js学习笔记(3)循环语句

热门文章

  1. Hooks中的useState
  2. bash历史命令数_如何使用Bash历史记录命令
  3. 开源软件的安全性风险_您的开源安全软件是否安全性较低?
  4. (2)vue.js介绍
  5. jQuery源码分析 Callbacks
  6. Bootstrap媒体对象列表
  7. 多传感器融合SLAM研究和学习专栏汇总
  8. Python 图片与字符串互转
  9. 计算机创新发展战略,计算机行业:《智能汽车创新发展战略》征求意见稿点评...
  10. mysql longblob_Mysql LONGBLOB 类型存储二进制数据 (修改+调试+整理)