部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

编程之美--2.16求数组中最长递增子序列

写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中的最长递增子序列的长度。

例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列为1,2,4,6

解法1:

遍历每个可能的子序列,判断是否为递增的。

//采用循环的方法,时间复杂度为O(N^2)
public static int LIS(int[] arr){
    int len = arr.length;
    int[] lenarr = new int[len];
    int tempi ;
    for(int i = 0 ; i < len ; i++){
        tempi = i ;
        lenarr[i]=1;
        for(int j = i+1 ; j < len ; j++){
            if(arr[tempi]<arr[j]){//后面的元素比当前元素大
                lenarr[i]++;
                tempi = j;
            }
        }
    }
    //输出递增长度数组
    MyPrint(lenarr);
    
    int maxlen = GetMax(lenarr);
    return maxlen;
}

解法2:类似解法1,比较的顺序不同

public static int LIS2(int[] arr){
    int len = arr.length;
    int[] lenarr = new int[len];
    for(int i = 0 ; i < len ; i++){
        lenarr[i]=1;
        for(int j = 0 ; j < i ; j++){
            if(arr[j]<arr[i]&&lenarr[j]+1 >lenarr[i]){
                lenarr[i] = lenarr[j]+1;
            }
        }
    }
    MyPrint(lenarr);

    int maxlen = GetMax(lenarr);
    return maxlen;
}

解法3:

在前面的分析中,当考察第i+1个元素的时候,我们是不考虑前面i个元素的分布情况的。现在我们从另一个角度分析,即当考察第i+1个元素的时候考虑前面i个元素的情况。
对于前面i个元素的任何一个递增子序列,如果这个子序列的最大的元素比array[i+1]小,那么就可以将array[i+1]加在这个子序列后面,构成一个新的递增子序列。
比如当i=4的时候,目标序列为1,-1,2,-3,4,-5,6,-7最长递增序列为(1,2),(-1,2)。
那么,只要4>2,就可以把4直接增加到前面的子序列中形成一个新的递增子序列。
因此,我们希望找到前i个元素中的一个递增子序列,使得这个递增子序列的最大的元素比array[i+1]小,且长度尽量地长。这样将array[i+1]加在该递增子序列后,便可以找到以array[i+1]为最大元素的最长递增子序列。
仍然假设在数组的前i个元素中,以array[i]为最大元素的最长递增子序列的长度为LIS[i]。
同时,假设:
长度为1的递增子序列最大元素的最小值为MaxV[1];
长度为2的递增子序列最大元素的最小值为MaxV[2];
……
长度为LIS[i]的递增子序列最大元素的最小值为MaxV[LIS[i]];

public static int LIS3(int[] arr){
    int len = arr.length;
    //记录数组中的递增序列信息
    //长度为1的递增子序列最大元素最小可以为MaxV[1]
    //长度为2的递增子序列最大元素最小可以为MaxV[2]
    int[] MaxV = new int[len];
    MaxV[1] = arr[0]; //数组中的第一值,边界值
    MaxV[0] = GetMin(arr)-1;     //数组中的最小值,边界值
    int[] lenarr = new int[len]; //以array[i]为最大元素的最长递增序列的长度为LIS[i]
    for(int i = 0 ; i < len ; i++){
        lenarr[i]=1;
    }
    int maxlen = 1;
    for(int i = 1 ; i < len ; i++){
        //遍历历史最长递增序列信息
        int j ;
        for(j=maxlen ; j>=0 ; j--){
            if(arr[i]>MaxV[j]){ //如果arr[i]大于长度为j的递增序列中的最大元素
                lenarr[i]=j+1;  //递增序列长度+1
                break;
            }
        }
        
        //如果当前最长序列的长度大于最长递增序列长度,更新最长信息
        if(lenarr[i] > maxlen){
            maxlen = lenarr[i];
            MaxV[lenarr[i]] = arr[i];
        }
        
        //如果长度为j的递增序列中的最大元素小于arr[i]并且arr[i]<长度为j+1的递增序列中的最大元素
        //则更新长度为j+1的递增序列中的最大元素为arr[i]
        else if(MaxV[j]< arr[i]&&arr[i]<MaxV[j+1]){
            MaxV[j+1]= arr[i];
        }
    }        
    MyPrint(lenarr);
    
    return maxlen;
}
//注意:可将内层循环改成下面的形式
//    for(j= lenarr[i-1] ; j >=1 ; j--){
//        if(arr[i]>MaxV[j]){
//            lenarr[i]=j+1;
//            break
//        }
//    }

 

辅助函数:

//获取数组最大值
public static int GetMax(int[] arr){
    int len = arr.length;
    int maxlen = arr[0];
    for(int i = 0 ; i < len ;i++){
        if(arr[i]>maxlen)
            maxlen = arr[i];

    }
    return maxlen;
}

//获取数组最小值
public static int GetMin(int[] lenarr){
    int len = lenarr.length;
    int min = lenarr[0];
    for(int i = 0 ; i < len ;i++){
        if(lenarr[i]<min)
            min = lenarr[i];

    }
    return min;
}

public static void MyPrint(int[] lenarr){
    for(int i = 0 ; i <lenarr.length ; i++){
        System.out.print(lenarr[i]);
    }
    System.out.println();
    
}

 

main函数:

public static void main(String[] args) {
    int[] arr = {1,-1,2,-3,4,-5,6,-7};
    System.out.println("解法1:最长递增数组长度为:"+LIS(arr));
    System.out.println("解法2:最长递增数组长度为:"+LIS2(arr));
    System.out.println("解法3:最长递增数组长度为:"+LIS3(arr));

}

结果:

44332211
解法1:最长递增数组长度为:4
11213141
解法2:最长递增数组长度为:4
11213141
解法3:最长递增数组长度为:4

注意三种方法的lenarr是不同的,原因是比较的顺序不同

posted @ 2015-06-21 18:50  流了个火  阅读(134)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats