1. 程式人生 > >最長遞增子序列(輸出最長遞增序列 及其長度)

最長遞增子序列(輸出最長遞增序列 及其長度)

最長遞增子序列的解法有很多種,常用的有最長公共子序列法、動態規劃、記錄所有遞增序列長度最大值的方法。

最長公共子序列法:如例子中的陣列A{5,6, 7, 1, 2, 8},則我們排序該陣列得到陣列A‘{1, 2, 5, 6, 7, 8},然後找出陣列A和A’的最長公共子序列即可。顯然這裡最長公共子序列為{5, 6, 7, 8},也就是原陣列A最長遞增子序列。

在http://blog.csdn.net/yysdsyl/article/details/4226630中有詳細解釋。

動態規劃:參見http://qiemengdao.iteye.com/blog/1660229

這裡主要介紹第三種方法:時間複雜度O(n lgn)

維護一個數組MaxV[i],記錄所有長度為i的遞增子序列中最大元素的最小值。
思路:遍歷陣列,如果陣列中該元素a[k]大於MaxV[len-1]的值,直接len++,MaxV[len]=a[k];

   否則從MaxV中從後向前,找到第一個比a[k]大的值的索引j,並將MaxV[j]更新為a[k](即長度為j的遞增序列最大值的最小值應為a[k]),查詢過程可以使用二分搜尋。

  為了記錄最大遞增序列,我們使用maxIndex記錄其索引,注意需要初始化maxIndex[0]=0;在a[k]>MaxV[len-1] 和 a[k]<MaxV[len-1]&&pos==len-1時,都需要更新maxIndex的值。

所以部落格http://blog.csdn.net/imzoer/article/details/8100064的解法是有問題的,這裡已經更正。

 1 //修改後的二分搜尋,返回從後向前,第一個比target大的索引 
 2 int bsearch(int *a, int s, int e,int target)
 3 {
 4     while(s<=e)
 5     {
 6         int mid = s +(e-s)/2;
 7         if(a[mid]<=target)
 8         {
 9             s=mid+1;
10         }
11 else 12 { 13 e = mid-1; 14 } 15 } 16 return s; 17 } 18 int getMaxSub(int *a, int n) 19 { 20 int *maxIndex = new int[n]; 21 int *maxV = new int[n]; 22 int len =1; 23 maxV[0] = a[0]; 24 maxIndex[0]=0; 25 for(int i=1; i <n; i++) 26 { 27 if(a[i]>maxV[len-1]) 28 { 29 maxV[len]=a[i]; 30 maxIndex[len]=i; 31 len++; 32 } 33 else 34 { 35 int pos = bsearch(a,0,len-1,a[i]); 36 maxV[pos]= a[i]; 37 if(pos == len-1) 38 maxIndex[pos]=i; 39 } 40 } 41 for(int i=0;i<len;i++) 42 { 43 printf("%d\t",a[maxIndex[i]]); 44 } 45 printf("\n"); 46 return len; 47 } 48 int main() 49 { 50 51 52 int a[]={ 53 7,5,4,2,3,5,6,1,5,8,9,10 54 }; 55 int b[]={ 56 1, 5, 8, 3, 6, 7, 2, 9 57 }; 58 printf("The array is :\n"); 59 for(int i=0;i<12;i++) 60 { 61 printf("%d\t",a[i]); 62 } 63 printf("\nThe max ascending array is:\n"); 64 printf("The length of max ascending array is :%d\n",getMaxSub(a,12)); 65 //getMaxSub(b,8); 66 67 }