算法导论之最长递增子序列

习题15.4-5,15.4-6:长度为n的数组,寻找最长递增子序列。要求(1)时间复杂度O(n^2) (2)时间复杂度O(n lg n) 

解:可以利用公共子序列来解,将数组a排序得到a',则a与a'的最大公共子序列即为所求,O(n * n)。下面的两种方法都是直接基于动态规划。

设输入序列为a[1 .. n],以a[i]作为最后一个元素的最长序列的长度为L[i],则L[i] = max{ L[j]+1 for j<i and a[j]<a[i] }。

计算出数组L之后如何反推出子序列呢?假设最大的L[i]是L[12]=5,那么子序列长为5,且最后一个元素是a[12]。从L[12]向前遍历,找到的第一个L[i]=4,那么a[i]就是倒数第二个元素。如下图所示。


时间复杂度为O(n*n)的算法见下面代码中的LongIncreaseSeq函数。

至于O(n lg n)的算法,对于所有长度为s的递增自序列,其中一定有一个是末尾元素最小的,将此最小末尾元素记录在MinEnd[s],那么根据书中提示易知,一定有MinEnd[1] < MinEnd[2] < ... < MinEnd[s] < MinEnd[s+1]。现在遍历a,对于每个a[i],用二分法找到a[i]在MinEnd中的插入位置s,即MinEnd[s-1] < a[i] <= MinEnd[s],那么可知将a[i]加在(s-1)的序列后面将得到长度为s的序列,又因为a[i] <= MinEnd[s],所以将MinEnd[s]更新为a[i]。在这个过程中还能顺便得到L数组。代码见函数LongIncreaseSeq_nlgn。

import bisect, random  

#L[i] = max{ length of increasing sequences end at a[i] }
def findSeq(a, L):
    seq = []
    curPos = L.index(max(L))
    seq.append(a[curPos])
    for i in range(curPos-1, -1, -1):
      if L[i] == L[curPos]-1:
        curPos = i
        seq.insert(0, a[curPos])
    return seq

#O(n * n)
def LongIncreaseSeq(a):
  L = [0]*len(a)
  for i in range(len(a)):
    longest = 1
    for j in range(i):
      if a[j] < a[i] and L[j]+1 > longest:
        longest = L[j]+1
    L[i] = longest
  print L
  print findSeq(a, L)
  return max(L)

#O(n * lg n)
def LongIncreaseSeq_nlgn(a):
  INF = max(a)+1
  #MinEnd[i] = min { end element for all increasing sequences of length i+1 }
  MinEnd = [INF]*len(a)
  L = [0]*len(a)
  for i in range(len(a)):
    j = bisect.bisect_left(MinEnd, a[i])
    MinEnd[j] = a[i]
    L[i] = j+1;
  print findSeq(a, L)
  return max(L)
  
a = [random.randint(0, 20) for i in range(15)]
print a
print LongIncreaseSeq(a)
print LongIncreaseSeq_nlgn(a)

参考资料:

http://blog.youkuaiyun.com/zhangguixian5/article/details/8205631

http://blog.youkuaiyun.com/sgbfblog/article/details/7798737

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值