Advertisement

算法导论15.4-6:最长单调递增子序列

阅读量:

参考文献:
《编程之美》一书中第2.16节
http://blog.pfan.cn/rickone/13086.html
http://chriszeng87.iteye.com/blog/1054321

设计一种时间复杂度为O(nlogn)的算法使其能够找到一个包含n个元素的序列中最长递增子序列

O(n²)相对容易理解;未加深入研究;后又研读了O(n log n)的具体解析以及众多大神的研究心得后才有所体会;也感受到其中奥秘无穷

对于序列{S_n},我们考虑其长度为i的所有单调递增或递减子列(其中1≤i≤m)。选择这些子列中最后一个元素的最小值,并将其记作L_i。则有以下关系式成立:L₁ ≤ L₂ ≤ … ≤ L_m。

序列a1, a2, …, an,从左至右扫描序列(可用二分法),对于每一个ai,它可能

(1) ai<L1,那么L1=ai

(2) ai>=Lm,那么Lm+1=ai,m=m+1 (其中m是当前见到的最大的L下标)

(3) Ls<=ai<Ls+1,那么Ls+1=ai

以上就是binarySrh中完成的主要任务。

数组a:1 3 5 2 3

通过改进后的二分查找方法确定了最长递增子序列的最大长度... 得到maxL数组中的值依次为1、2、3... 其中maxL数组中元素的数量len直接对应于最长递增子序列的长度... 对于这一点我也仅能有所体会而非深入论证

2、如果要得到子序列的内容应该怎么做呢?

可以在遍历过程中,在每一步中通过mem数组记录当前处理过的元素及其对应的最长递增子序列长度j(其中j代表该位置对应的最长递增子序列的长度)。当整个过程结束后,在逆序访问该数组时即可依次获取长度依次递减至1的所有最长递增子序列的结尾元素,并最终确定了完整的最长递增子序列结构。

复制代码
 #include<iostream>

    
 using namespace std;
    
  
    
 int binarySrh( int *s, int len, int x ) #二分查找
    
 {
    
 	int left = 0,right = len-1, mid = (left+right)/2;
    
 	while( left<=right )
    
 	{
    
 		if( x>s[mid] )	left = mid+1;
    
 		else if( x<s[mid] ) right = mid-1;
    
 		else return mid;
    
 		mid = (left+right)/2;
    
 	}
    
 	cout << left << ' ';
    
 	return left;
    
 }
    
  
    
 int main()
    
 {
    
 	int n = 10;//原始数组长度
    
 	int a[10] = { 6, 1, 8, 3, 10, 11, 12, 13,  4, 5 };
    
 	int maxL[10] = { 0 };//maxL[i]记录长度为i子序列的最小尾数
    
 	int mem[10] = { 0 };//mem[i]表示以a[i]结尾的最长子序列
复制代码
  maxL[0] = a[0];

    
 	int len = 1;//length
    
 	
    
 	for( int i=1; i<n; i++ )
    
 	{
    
 		int j = binarySrh( maxL, len, a[i] );
    
 		maxL[j] = a[i];
    
 		mem[i] = j;
    
 		if( ++j>len )
    
 			len = j;
    
 	}
    
 	cout << "max length: " << len << endl;
    
 	cout << "longest subsequence: ";
    
 	int currMaxLen = len-1;
    
 	for( int i=0; i<n; i++ )
    
 		cout << mem[i] << " ";
    
 	cout << endl;
    
 	for( int i=9; i>=0&&currMaxLen>=0; i-- ) {
    
 		if( mem[i]==currMaxLen ) {
    
 			cout << a[i] << " "; //反向输出子序列
    
 			currMaxLen--;
    
 		}
    
 	}
    
 	cout << endl;
    
 	return 0; 
    
 }
复制代码
复制代码
复制代码

全部评论 (0)

还没有任何评论哟~