1. 程式人生 > >【演算法】最長遞增子序列的長度

【演算法】最長遞增子序列的長度

題目

求一個一維陣列a[i]中的最長遞增子序列的長度,如在序列1,-1,2,-3,4,-5,6,-7中,最長遞增子序列長度為4,可以是1,2,4,6,也可以是-1,2,4,6。

演算法思路

演算法一(簡單暴力)

/**
用b[]記錄當前最長遞增子序列長度,b[i]表示a[0,...,i]中的最長遞增子序列長度;
求b[i],就是從後向前分析,第i個元素的最長遞增子序列的長度要麼是1(單獨成一個序列),要麼就是第i-1個元素之前的最長遞增子序列加1
**/
public class  LongestIncreasingSubsequence{
   public static void
main(String[] args) { int a[]={1,-1,2,-3,4,-5,6,-7};//陣列 int len = a.length;//陣列長度 int b[]=new int[len];//b[i]表示a[0,...,i]中的最長遞增子序列長度 for(int i=0;i<len;i++){//初始化為1 b[i]=1; } int max=1;//記錄最大遞增子序列長度 for(int i=1;i<len;i++){ for(int j=i-1;j>=0;j--){//尋找i-1前的最長子序列長度
if(a[i]>a[j]&&b[i]<b[j]+1){//更新最大值,作為i的最長子序列長度 b[i]=b[j]+1; } } if(max<b[i]){ max=b[i]; } } System.out.println(max); } }

時間複雜度為o(n2)

演算法二(快速排序+最長公共子串)

不難理解,對於原陣列所求的最長遞增子序列,在陣列按遞增排序之後,也是有序陣列的最長遞增子序列。
比如a[]={1,-1,2,-3,4,-5,6,-7}
排序之後:a1[]={-7,-5,-3,-1,1,2, 4,6}
則a和a1的最長公共子序列是是1,2,4,6,也可以是-1,2,4,6。而這個也正是a陣列的最長遞增子序列
所以該演算法分為兩個步驟,先排序,得到陣列a1,之後求兩陣列公共子序列。
時間複雜度o(nlogn)+o(n

2)=o(n2)

演算法三(二分查詢)

/**
maxVal陣列是記錄最大遞增子序列的陣列,嚴格來說,其元素並不是最大遞增子序列,但是其元素具有求解最大遞增子序列長度的意義。
l是maxVal陣列有效長度,也是最終求得最大遞增子序列長度
演算法估計難以用語言描述,但是可以舉個例子:
a[]={1,-1,2,-3,4,-5,6,-7}
i=0,初始化:maxVal={1},l=1;
i=1,a[i]=-1<maxVal[l-1],則查詢maxVal陣列中是否存在a[i],如果不存在就用a[i]替換maxVal從0到l-1元素中第一個大於a[i]的元素,所以maxVal={-1}
i=2,a[i]=2>maxVal[l-1],則直接將a[i]加入maxVal中即maxVal[l++]=a[i],則maxVal={-1,2},l=2
i=3,a[i]=-3<maxVal[l-1],查詢maxVal陣列中是否存在a[i],如果不存在就用a[i]替換maxVal從0到l-1元素中第一個大於a[i]的元素,所以maxVal={-3,2}
i=4,a[i]=4>maxVal[l-1],則直接將a[i]加入maxVal中即maxVal[l++]=a[i],則maxVal={-3,2,4},l=3
i=5,a[i]=-5<maxVal[l-1],查詢maxVal陣列中是否存在a[i],如果不存在就用a[i]替換maxVal從0到l-1元素中第一個大於a[i]的元素,所以maxVal={-5,2,4}
i=6,a[i]=6>maxVal[l-1],則直接將a[i]加入maxVal中即maxVal[l++]=a[i],則maxVal={-5,2,4,6},l=4
i=7,a[i]=-7<maxVal[l-1],查詢maxVal陣列中是否存在a[i],如果不存在就用a[i]替換maxVal從0到l-1元素中第一個大於a[i]的元素,所以maxVal={-7,2,4,6}
所有過程結束,l就是最長遞增子序列的長度為4
上面查詢則是用簡單的二分查詢法,具體程式碼如下:
**/
public class LongestIncreasingSubsequence {
   public static void main(String[] args) {
       int a[]={1,-1,2,-3,4,-5,6,-7};
       int len = a.length;
       int maxVal[] = new int[len];
       maxVal[0]=a[0];
       int l=1;
       for(int i=1;i<len;i++){
           if(a[i]>maxVal[l-1]){
               maxVal[l++]=a[i];
           }else{
               int pos = binSearch(a,0,l-1,a[i]);
               maxVal[pos]=a[i];
           }
       }
       System.out.println(java.util.Arrays.toString(maxVal));
       System.out.println(l);
    }

    private static int binSearch(int[] a, int left,int right,int x) {
        while(left<=right){
            int mid = (left+right)/2;
             if(a[mid]<=x){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return left;
    }
}

時間複雜度o(nlogn)