引出:

问题描述:给出一个序列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. jmeter 实现登录一次,多次操作登录后的某一个功能

  2. HTML <area><map>标签及在实际开发中的应用

    之前,我一直以为HTML <area>是一个鸡肋HTML,估计到了HTML5时代会被废弃的命.但是,最近一查资料,乖乖了个咚,不仅没被废弃,反而发展了,新增了一些标签属性,例如rel,me ...

  3. javascript计算啤酒2元一瓶,4个盖换一瓶,2个瓶换一瓶,10元钱最多喝多少瓶

    var n = 0//当前剩下多少瓶加上喝赢了多少瓶 var x = 5//初始多少瓶 var y = 0//除了喝掉的,剩下多少瓶 var z = 0;//总数 var arr = []//定义一个 ...

  4. FPGA学习:VHDL设计灵活性&不同设计思路比较

    概要 由于VHDL编程实现数字电路具有很高的灵活性,为多种不同的思路编写实现同一种功能提供了可能.这些不同的设计思路,在耗费资源,可靠性,速度上也有很大的差异,往往需要我们根据实际需求和资源条件选择适 ...

  5. SpringBoot学习开篇

    "Spring Framework已有十余年的历史了,已成为Java应用程序开发框架的事实标准.在如此悠久的历史背景下,有人可能会认为Spring放慢了脚步,躺在了自己的荣誉簿上,再也做不出 ...

  6. C# 引用类型之特例string

    在C#编程的时候经常会使用字符串(string)类型,它也是引用类型,但是处处都不作为引用的用法来使用,实属特例,下来我一一罗列出来,供自己记忆方便: 1)字符串的直接赋值:本身字符串就是引用类型,应 ...

  7. 软工+C(2017第3期) 超链接

    // 上一篇:分数和checklist // 下一篇:Alpha/Beta换人 注:平常看文章,总有能和构建之法,软件工程相关的链接,增量记录,也可以通过在其他人博客的交流中使用相关的超链接,在使用中 ...

  8. 结对编程-四则运算-GUI

     201421123022 王若凡        201421123026  欧阳勇 https://git.coding.net/ttoyy/sizeyunsuan-GUI.git a.需求分析: ...

  9. 201521123097《Java程序设计》第八周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 1.本次作业题集集合 public static List return str; } pub ...

  10. 201521123001《Java程序设计》第7周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 答: 大多数情况下,从性能上来说ArrayList最好,但是当集合内的元素需要频繁插入.删除时Lin ...