Longest Increasing Subsequence(LIS)

    已知集合A[1...n],求最长上升(递增、单调增)子序列。较为常见的DP问题,实际上就是求以求Ai开始的最长子序列(1<=i<=n)。但关键是分解子问题,求原问题的最优解转化为求子问题的最优解,然后描述子问题,根据子问题的描述寻求最优解的递推关系,然后计算最优解,最终重构原问题的最优解。

    关于LIS问题,一般化的子问题可以描述为:集合Aij(i<=j),以Ai开始的LIS(i,j)是从Ai+1开始的第一个大于Ai的元素Ak(i<k<=j)开始的集合的LIS(k,j)+1,应满足条件存在k(i<k<=j)使得Ak>Ai,只要满足此条件,则LIS(k,j)也是最优解,可以采用cut-and-paste以及反证法证明(设LIS(i,j)=l,则满足条件存在k(i<k<=j)使得Ak>Ai的LIS(k,j)=l-1,如果LIS(k,j)不是最优解,即存在m(i<m<=j)使得Am>Ai,有LIS(m,j)>l-1,从而替换掉原来A(i,j)中的部分解使得LIS(i,j)>l,与LIS(i,j)是最优解矛盾);否则LIS(i,j)=1。个人认为这种描述尽管忠于原问题的描述,但在实现时稍稍复杂。因此,可以考虑如下的描述。

    LIS问题实际上是一个特殊的计数问题,即对于集合Aij,对于Am(i=<m<=j),统计Ak(m+1<=k<=j)可以在LIS序列中作为Am(i=<m<=j)的后继的计数问题,LIS(i,j)问题即是求这些计数中的最大值。子问题的求解递推关系d(k)=max{d(k), d(m)+1}(Ak>Am)<这个问题可以这样来考虑,假如LIS(i,m)是Aim集合的LIS,那么只要存在Ak>Am(m+1<=k<=j)就有可能使原以Am结尾现以Ak结尾的上升子序列的长度增加1(d(k)=max{d(k), d(m)+1});对Am(i=<m<=j)依次统计便求得分别以Am结尾的上升子序列的长度,因此LIS问题即是求max{d(k)}。>;为方便回溯求解LIS序列,可采用向量pre来记录Ak的前驱。算法描述如下:

1. for i =1 to n
2.     d(i) = 1   {每个元素本身可以看作长度为1的子序列
3. for i = 1 to n
4.     pre(i) = -1 {-1表示a(i)没有前驱}
5. for i = 1 to n
6.     for j = i+1 to n
7.         if  a(j)>a(i) then   {a(j)可以作为a(i)的后继
8.             if d(i)+1 > d(j) then
9.                 d(j) = d(i)+1    {可以作为后继则计数+1,这里就体现了递推关系}
10.               pre[j] = i  {j的前驱是i}
11.           end if
12.       end if
13.    end for
14. end for
15. for i = 1 to n
16.     max = max{d(i)}
17. end for
18. return max

    算法的时间复杂性为O(n^2),空间复杂性为O(n)。

    关于子问题的描述还有另一种描述方法,对于集合Aij(i<=j),LIS问题可转化为,对于Am(i<=m<=j),统计Ak(i<=k<=m-1)在LIS序列中可以作为Am的前驱的计数问题,LIS(i,j)问题即是求这些计数中的最大值。

 

关于更为详细的代码以及另一种子问题(对于集合Aij,对于Am(i=<m<=j),统计Ak(i<=k<=m-1)可以在LIS序列中作为Am的前驱的计数问题,LIS(i,j)问题即是求这些计数中的最大值。)描述可以参考:http://www.csie.ntnu.edu.tw/~u91029/LongestIncreasingSubsequence.html

http://scnuznh.blog.hexun.com/18145559_d.html

另外关于O(nlogn)的算法可以参考:

http://hi.baidu.com/napolengogo/blog/item/5c87b53559a1cf335bb5f596.html

http://www.slyar.com/blog/longest-ordered-subsequence.html

http://en.wikipedia.org/wiki/Longest_increasing_subsequence

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值