LIS和LCS
来源:互联网 发布:培罗成西服淘宝店 编辑:程序博客网 时间:2024/05/21 04:25
LIS LCS n^2和nlogn解法 以及LCIS
http://www.cnblogs.com/gj-Acit/p/3236384.html
首先介绍一下LIS和LCS的DP解法O(N^2)
LCS:两个有序序列a和b,求他们公共子序列的最大长度
我们定义一个数组DP[i][j],表示的是a的前i项和b的前j项的最大公共子序列的长度,那么由于是用迭代法,所以计算DP[i][j]前,DP[i-1][j]和DP[i][j-1]就都已经计算出来了,不难理解就可以得出状态转移方程:
DP[i][j] = DP[i-1][j-1] + 1; 如果a[i] == b[j]
MAX(DP[i-1][j], DP[i][j-1]) 如果a[i] != b[j]
LIS:一个a序列,求它的最长上升子序列的最大长度
另外,由于每次都是扫描b数组,那我们就只需要一个DP[2][B]的数组就可以了,DP[0][]依赖于DP[1][],DP[1][]依赖于DP[0][],只要实现动态处理就可以了。
这个状态转移方程也不难给出
DP[j] = MAX(DP[i]) + 1 满足条件a[j] > a[i]
对每一个a[j],枚举一遍a[0]....a[j-1]就可以了
下面再来看看他们的O(nlogn)的解法
首先是LCS,我们把a序列中的每个元素在b中出现的位置保存起来,再按照降序排列,排列后再代入a的每个对应元素,那就转化为了求这个新的序列的最长上升子序列了。如:a[] = {a, b, c,} b[] = {a,b,c,b,a,d},那么a中的a,b,c在b中出现的位置分别就是
{0,4},{1,3},{2}分别按降序排列后代入a序列就是{4,0,2,3,1},之所以要按照降序排列,目的就是为了让每个元素只取到一次。
接下来的问题就是要求最长升序子序列问题了,也就是求LIS。
PS:个人认为这种转化并没有多大意义,因为当数据比较大时,举一个例子来说:a[]= “aaaaaaaaaaa”,b[] = "aaaaaaaaaaa",他们都有n个a,那么a[]中‘a’在b[]出现了n次那么替换之后的a就变为了n-1...1,n-1...1,... ...这样a[]就有了n^2个数了这样不仅是空间,就连时间也比原来n^2要大。所以感觉这种转化还是要慎用。
一、算法思想
算法还是容易想到的,两重循环DP即可。不过如果数据规模最大可以达到几十万甚至更大,经典的O(n^2)的动态规划算法明显会超时。我们需要寻找更好的方法来解决是最长上升子序列问题。以下以最长递增子序列为例进行说明:
先回顾经典的O(n^2)的动态规划算法,设A[i]表示序列中的第i个数,F[i]表示从1到i这一段中以i结尾的最长上升子序列的长度,初始时设 F[i] = 0(i = 1, 2, ..., len(A))。则有动态规划方程:F[i] = max{1, F[j] + 1} (j = 1, 2, ..., i - 1, 且A[j] < A[i])。
现在,我们仔细考虑计算F[i]时的情况。假设有两个元素A[x]和A[y],满足(1)y < x < i (2)A[x] < A[y] < A[i] (3)F[x] = F[y]
此时,选择F[x]和选择F[y]都可以得到同样的F[i]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢?
很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[i-1]这一段中,如果存在A[z],A[x] < A[z] < A[y],则与选择A[y]相比,将会得到更长的上升子序列。
再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[i] = k的所有A[i]中的最小值。设D[k]记录这个值,即D[k] = min{ A[i] } ( F[i] = k )。
注意到D[]的两个特点:
(1) D[k]的值是在整个计算过程中是单调不上升的。//此处需要特别注意!!!关键之所在!
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。
利 用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[i]与D[len],若A[i] > D[len],则将A[i]接在D[len]后将得到一个更长的上升子序列,len = len + 1,D[len+1] = A[i];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[i].令k = j + 1,则有D[j] < A[i] <= D[k],将A[i]接在D[j]后将得到一个更长的上升子序列,同时更新D[k] = A[i].最后,len即为所要求的最长上升子序列的长度。
在上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于 共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),与原来的算法相比没有任何进步.但是由于D[]的特 点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法的时间复杂度下降为O(nlogn),有了非常显著的提高.需要注意的 是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列.
这个算法还可以扩展到整个最长子序列系列问题,整个算法的难点在于二分查找的设计,需要非常小心注意.
- LIS和LCS
- LIS和LCS
- LCS && LIS
- LIS+LCS~
- LCS?LIS
- LIS&&LCS
- 对 LCS 和 LIS 的总结
- 动态规划之LCS和LIS
- LCS,LIS(王子和公主,uva 10635)
- LIS,LCS,一道LIS题
- Uva 10635 王子和公主(LCS转LIS+二分)
- LIS LCS n^2和nlogn解法 以及LCIS
- ***转载 LIS LCS n^2和nlogn解法 以及LCIS
- [DP]LIS+LCS+最大连续子段和
- uva10635 王子和公主(把lcs转化为lis)
- LIS LCS n^2和nlogn解法 以及LCIS
- 算法(一) --DP动态规划(LIS和LCS)
- LCS/LIS/LCIS
- code_snippet 自定义代码块
- 基于微服务的软件架构模式
- objective-c之struct
- 第一天开启CSDN博客之旅
- poj3020 Antenna Placement
- LIS和LCS
- 文章标题
- 2016多校第五场 1001 HDU 5781 DP
- 堆的实现andprioity-queue函数
- 弹性盒子flex布局实现骰子六个面并让骰子3D空间旋转
- 剑指offer 约瑟夫环问题
- BZOJ 2440 完全平方数(莫比乌斯反演+容斥原理+二分)
- iOS开发之获取APP在AppStore中的版本号
- asp.net从零开始---002--前端页面布局