算法导论之最长递增子序列
2014-06-11 20:47
357 查看
习题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。
参考资料:
/article/8604735.html
/article/2939893.html
解:可以利用公共子序列来解,将数组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)
参考资料:
/article/8604735.html
/article/2939893.html
相关文章推荐
- 算法导论15.4-5、6 最长递增子序列(n平方)和(nlogn)
- FZU2236 求最长递增子序列的个数----树状数组记录位置
- 最长递增子序列
- 动态规划--最长递增子序列
- 求最长递增子序列
- 每日一题(79) - 求数组中最长递增子序列
- 求数组的最长严格递增子序列
- HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典
- LeetCode--Longest Increasing Subsequence (最长递增子序列)Python
- [转]最长递增子序列问题的求解
- 求数组中最长递增子序列(编程之美2.16)
- 编辑距离,最长公共子序列,最长公共子串,最长递增子序列
- 动态规划之最长递增子序列
- pku 1836 Alignment(最长递增子序列)
- 最长连续递增子序列
- 关于动态规划解题步骤和两个重要性质的理解---以最长递增子序列为例
- 递增子序列最大和(最长递增子序列) 动态规划
- 求数组中最长递增子序列
- Cogs 731. [网络流24题] 最长递增子序列(最大流)
- AOJ-AHU-OJ-189 最长递增子序列(模拟+二分查找)