最长递增子序列问题

一 问题描述

设序列L = <a1, a2, a3, ..., an>是长度为n的序列,L的一个递增序列描述为:<ai1, ai2,..., aik>, 其中下标序列 <i1, i2, ..., ik>是

递增的, 子序列<ai1, ai2, ...., aik> 也是递增的。此递增序列的长度为 k


二 解法1, 转化为LCS问题

先把序列 L 按照从小到大的顺序排列, 得到另一个序列S,再求L和S的最长公共子序列


三 解法2,动态规划

另 len[i] 表示以第 i 个元素结尾的最长递增子序列的长度,最后求出 max { len[i] } 即可

实例 <1, 3, 4, 2, 7>

len[1] = 1, 以1结尾的最长递增子序列是<1>, 长度为1

len[2] = 2, 以3结尾的最长递增子序列是<1,3>, 长度为2

len[3] = 3, 以4结尾的最长递增子序列是<1, 3, 4>, 长度为3

len[4] = 2, 以2结尾的最长递增子序列是<1, 2>,长度为2

那么,如何求len[5]呢?转化为下面的子问题:

第5个元素等于7,找到一个序号在a[5]前面且小于a[5]的元素a[i], 以a[i]结尾的最长递增子序列加上a[5], 组成一个新的最长递增子序列,其

长度比原来的多1。比a[5]小的元素有多个(最多4个),那么得到的递增子序列也有多个,其中最长的那个就等于以a[5]结尾的最长递增子序列。

例中,a[3 ]比a[5]小,而且以a[3]结尾的最长递增子序列是最长的, 故以a[5]结尾的递增子序列长度在其基础上加1,等于4

len[5] = 4, 以5结尾的最长递增子序列是<1,3,4,5>,长度为4


四 解法3,对解法2的改进

解法2中,求len[i]的时候, 要从a[1], ... a[i-1]中找出所有比 a[i] 小的元素,而a[1], ... a[i-1]是无序的。查找速度比较慢。

引出数组 f[k] 表示长度等于k的递增子序列中最末尾的元素, 长度越长的序列,其末尾元素也越大,所以f[k]是递增的。

实例 <1, 3, 4, 2, 7>

len[1] = 1, f[1] = a[1] = 1

len[2] = 2, f[2] = a[2] = 3

len[3] = 3, f[3] = a[3] = 4

len[4] = 2, f[2] = a[4] = 2 ( 更新了f[2] )

那么,如何求len[5] 呢?

f[1] = 1, f[2] = 2, f[3] = 4, a[5] = 7,

找出末尾元素比a[5]小,而且长度最长的递增子序列,此例中,

f[3] = 4 表示长度等于3的子序列,其末尾元素为4,这个子序列的长度最长。

a[5]加上此序列形成的新序列长度为4, 然后更新f[4] = a[5] = 7,表示长度

等于4的子序列,其末尾元素等于7

在上面的步骤中,找出末尾元素比a[i]小,而且长度最长的子序列,其实就是

对于f[1], ...f[k], 从后往前找,第一个比a[i]小的元素就是长度最长的子序列。查找的时候

可以用二分查找方法。故比解法1更快。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值