引出:

问题描述:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1<s2<s3<…<sn并且这个子序列的长度最长。输出这个最长的长度。(为了简化该类问题,我们将诸如最长下降子序列及最长不上升子序列等问题都看成同一个问题,其实仔细思考就会发现,这其实只是<符号定义上的问题,并不影响问题的实质)
例如有一个序列:1  7  3  5  9  4  8,它的最长上升子序列就是 1 3 4 8 长度为4.

分析:

这题目是经典的DP题目,也可叫作LIS(Longest Increasing Subsequence)最长上升子序列 或者 最长不下降子序列。很基础的题目,有两种算法,复杂度分别为O(n*logn)和O(n^2) 。

算法1:
时间复杂度:O(n^2):
我们依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1, i-1]); 显然dp[1]=1,我们从i=2开始遍历后面的元素即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Author: Tanky Woo
// Blog: www.WuTianQi.com
int dp[];
int LIS(int arr[], int n)
{
for(int i=; i<=n; ++i)
dp[i] = ;
int ans;
dp[] = ;
for(int i=; i<=n; ++i)
{
ans = dp[i];
for(int j=; j<i; ++j)
{
if(arr[i]>arr[j] && dp[j]>ans)
ans = dp[j];
}
dp[i] = ans+;
}
ans = ;
for(int i=; i<=n; ++i)
{
if(dp[i] > ans)
ans = dp[i];
}
return ans;
}

算法2:
时间复杂度:(NlogN):
除了算法一的定义之外,增加一个数组b,b[i]用以表示长度为i最长子序列的最后一个数最小可以是多少。易证:i<j时,b[i]<b[j]。
在二分查找时,一直更新b[]内容,设此时b的总长度为k,
若1. arr[i] >= b[k], 则b[k+1] = arr[i];
若2. arr[i] <  b[k], 则在b[1..k]中用二分搜索大于arr[i]的最小值,返回其位置pos,然后更新b[pos]=arr[i]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Author: Tanky Woo
// Blog: www.WuTianQi.com
// num为要查找的数,k是范围上限
// 二分查找大于num的最小值,并返回其位置
int bSearch(int num, int k)
{
int low=, high=k;
while(low<=high)
{
int mid=(low+high)/;
if(num>=b[mid])
low=mid+;
else
high=mid-;
}
return low;
}
 
int LIS()
{
int low = , high = n;
int k = ;
b[] = p[];
for(int i=; i<=n; ++i)
{
if(p[i]>=b[k])
b[++k] = p[i];
else
{
int pos = bSearch(p[i], k);
b[pos] = p[i];
}
}
return k;
}

以下是证明b[]的单调递增性:
b序列是严格递增的,即b[1] < b[2] < … < b[t]。
证明:
若b[i] >= b[i + 1],b[i + 1] 是长度为i+1的递增子序列的尾项的最小值,设此序列为x[1]..x[i+1],x[1]..x[i]即构成长度为i的递增子序列,x[i] < x[i+1] = b[i+1] <= b[i],与b[i]定义不符。

最后,给出两个有代表性的题目:

1.HDOJ 1257 最少拦截系统

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1257

解题报告传送门:http://www.wutianqi.com/?p=1841

此题用O(n^2)解法做即可。

2.HDOJ 1025  Constructing Roads In JGShining’s Kingdom

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1025

解题报告传送门:http://www.wutianqi.com/?p=1848

此题数据量较大,所以要用O(NlogN)的解法做。

最长上升子序列 LIS(Longest Increasing Subsequence)的更多相关文章

  1. 最长递增子序列 (LIS) Longest Increasing Subsequence

    问题描述: 有一个长为n的数列a0, a1,..., an-1.请求出这个序列中最长的上升子序列.请求出这个序列中最长的上升子序列. 上升子序列:对于任意i<j都满足ai<aj的子序列. ...

  2. 最长上升子序列(Longest increasing subsequence)

    问题描述        对于一串数A={a1a2a3…an},它的子序列为S={s1s2s3…sn},满足{s1<s2<s3<…<sm}.求A的最长子序列的长度. 动态规划法 ...

  3. LeetCode 300. 最长上升子序列(Longest Increasing Subsequence)

    题目描述 给出一个无序的整形数组,找到最长上升子序列的长度. 例如, 给出 [10, 9, 2, 5, 3, 7, 101, 18], 最长的上升子序列是 [2, 3, 7, 101],因此它的长度是 ...

  4. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  5. 最长上升子序列(LIS: Longest Increasing Subsequence)

    示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4. 从网上找的一段代码(我由java改为了C++版本),原作者 ...

  6. C#LeetCode刷题之#594-最长和谐子序列​​​​​​​​​​​​​​(Longest Harmonious Subsequence)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3800 访问. 和谐数组是指一个数组里元素的最大值和最小值之间的差 ...

  7. About LIS(Longest Increasing Subsequence)

    今天528给讲了基础的DP,其中第一道例题就是最长不下降子序列——LIS. 题目简述:给出N个数,求最长不下降子序列的长度. 数据范围:30% N<=1000 ; 100% N<=1000 ...

  8. 动态规划之最长公共子序列LCS(Longest Common Subsequence)

    一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...

  9. 动态规划 ---- 最长公共子序列(Longest Common Subsequence, LCS)

    分析: 完整代码: // 最长公共子序列 #include <stdio.h> #include <algorithm> using namespace std; ; char ...

随机推荐

  1. Tomcat session集群

    author:JevonWei 版权声明:原创作品 环境 tomcatA 172.16.253.108 tomcatB 172.16.253.105 代理服务器 172.16.253.191 Tomc ...

  2. 如何将ASP.NET-WebApi发布到IIS6.0上(转)

    关于"如何将ASP.NET-WebApi发布到IIS6.0上"的这方面的学习,一开始项目组长让我们接触的时候,我的心情是这样的 哇呜.jpg 当时真的是一脸懵逼啊,对于刚接触asp ...

  3. 【全面总结】js获取元素位置大小

    [js获取元素位置+元素大小]全面总结 目录 1.关于offset offsetParent(只读) offsetTop(只读) offsetLeft(只读) offsetHeight(只读) off ...

  4. 后台方庄List razor 循环

    后台: //1.查询所有年卡类型                StringBuilder sqlStr = new StringBuilder();                sqlStr.Ap ...

  5. base(function strchr)

    函数原型:extern char *strchr(char *str,char character) 参数说明:str为一个字符串的指针,character为一个待查找字符.        所在库名: ...

  6. bgp选路原则【第二部】

    面向逻辑谈bgp选路原则(第二部) 终于到了BGP终极解析的第二部曲--BGP选路原则.与题目相呼应,我不会直接介绍选路原则的规则,而是从时间逻辑和空间逻辑上将所有的选路原则分层分类.因为只有从这种角 ...

  7. js中面向对象的写法

    function Circle(r){ this.r = r; }//构造(实例对象的)函数[思路二:这是一个类] Circle.PI = 3.14159; //属性 Circle.prototype ...

  8. Java多线程之Executor、ExecutorService、Executors、Callable、Future与FutureTask

    1. 引子 初学Java多线程,常使用Thread与Runnable创建.启动线程.如下例: Thread t1 = new Thread(new Runnable() { @Override pub ...

  9. [2017BUAA软工助教]评论汇总

    一 邹欣 周筠 飞龙 二 学校 课程 教师 助教1 助教2 助教3 福州 软件工程1715K 柯逍 谢涛 软件工程1715Z 张栋 刘乾 汪培侨 软件工程1715W 汪璟玢 曾逸群 卞倩虹 李娟 集美 ...

  10. 201521123114 《Java程序设计》第4周学习总结

    1. 本章学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 学会了设计一个类时,尽量用private修饰属性,public修饰方法:类名的首字母要大写. ...