最长递增子序列

解法一:通过排序,使其转化为lcs问题

import java.util.Arrays;

public class LastStr {

    public static void main(String[] args) {
        int []arr ={0,3,1,4,1,5,9,2,6,5};
        int []arrSort =arr.clone();
        int[][]b= new int[arr.length][arrSort.length];
        int [][]c = new int[arr.length][arrSort.length];
        for(int i=0;i<arr.length;++i){
            c[i][0]=0;
        }
        for(int j=0;j<arrSort.length;++j){
            c[0][j]=0;
        }
        Arrays.sort(arrSort);
        maxStr(arr, arrSort,c,b);
        check(b, arr, arr.length-1, arrSort.length-1);
    }
    
    public static void maxStr(int[]arr,int[]arrSort,int [][]c,int[][]b){

        
        for(int i=1;i<arr.length;++i){
            for(int j=1;j<arrSort.length;++j){
                if(arr[i]==arrSort[j]){
                    c[i][j]=c[i-1][j-1]+1;
                    b[i][j]=1;
                }else if(c[i-1][j]>=c[i][j-1]){
                    c[i][j]=c[i-1][j];
                    b[i][j]=2;//"↑"
                }else{
                    c[i][j]=c[i][j-1];
                    b[i][j]=3;
                }
            }
        }

        System.out.println(c[arr.length-1][arrSort.length-1]);
    }
    
    public static void check(int[][]b,int[]arr,int i,int j){
        if(i==0||j==0)
            return;
        if(b[i][j]==1){
            check(b, arr, i-1, j-1);
            System.out.print(arr[i]+" ");
        }
        else if(b[i][j]==2){
            check(b, arr, i-1, j);
        }else{
            check(b, arr, i, j-1);
        }
        
    }
}

 解法二:

另一种方式是直接用DP求解,算法如下:时间复杂度为O(N^2)

①最优子问题

设lis[i] 表示索引为 [0...i] 上的数组上的 最长递增子序列。初始时,lis[i]=1,注意,在DP中,初始值是很重要的,它是整个算法运行正确的关键。而初始值 则可以 通过 画一个小的示例来 确定。

当 arr[i] > arr[j],lis[i] = max{lis[j]}+1 ;其中,j 的取值范围为:0,1...i-1

当 arr[i] < arr[j],lis[i] = max{lis[j]} ;其中,j 的取值范围为:0,1...i-1

 

②重叠子结构

从上面可以看出,计算 lis[i]时,需要计算 lis[j],其中 j < i,这说明有重叠子问题。借用网路中一张图如下:

复制代码
                     lis(4)           
                 /       |      \
         lis(3)      lis(2)    lis(1)  
        /     \        /         
  lis(2)  lis(1)   lis(1) 
  /    
lis(1)
复制代码

而初始值 则可以 通过 画一个小的示例来 确定。

public class LIS {
    public static int lis(int[] arr){
        if(arr == null || arr.length == 0)
            return 0;
        return lis(arr, arr.length);
    }
    
    private static int lis(int[] arr, int length){
        int lis[] = new int[length];
        
        //init
        for(int i = 0; i < length; i++)
            lis[i] = 1;
        
        for(int i = 1; i < length; i++)
        {
            for(int j = 0; j < i; j++)
            {
                if(arr[i] > arr[j] && lis[j] + 1 > lis[i])  //arr[i]要大于 j belongs to  0,1,...i-1 中所有的 arr[j]中的最大值,
                                   //并且 lis[i] 是该最大值 arr[j] 所对应的 lis[j] +1,而不是某个其他的arr[j] 对应的 lis[j]+1 lis[i]
= lis[j] + 1; } } int max = lis[0]; for(int i = 1; i < length; i++) if(max < lis[i]) max = lis[i]; return max; } public static void main(String[] args) { int[] arr = {3,1,4,1,5,9,2,6,5}; int result = lis(arr); System.out.println(result); } }

 

posted @ 2017-03-31 15:40  mslog  阅读(130)  评论(0编辑  收藏  举报