最长非降子序列

定义:一个包含n个数的序列a0, a1, ... , an-1,求序列的最长非降(>=)子序列及其长度。

如:序列5, 3, 4, 9, 6, 8,此最大非降子序列长度为4,子序列为3,4,6,8.(子序列也可能不唯一)

 

运用动态规划,可以构造时间复杂度为O(n2)的算法。

 

算法基本思路:

1.打表,获取最长非降子序列的长度;

要构造最长非降子序列,可知此序列一定是以序列中某个数作为结尾(好像是废话,但就是那样)。

因此,构造表ml[0...n-1],ml[i] 表示前 i 个数以a[i] 为结尾的最长非降子序列的长度。

枚举 j (0 <= j < i),若a[j] <= a[i],则a[i]可在以a[j]为结尾的非降子序列后添加,此序列长度为ml[j] + 1.

因此ml[i] = max(ml[j] + 1) (0 <= j < i) .

构造出表ml后,遍历ml表,获取最大值。

 

2.获取最长非降子序列的一个解。

这个相当简单。只需要在构造表ml的过程中,添加表pre[0...n-1],pre[i] 保存当前a[i]为结尾的非降子序列的前一个元素的编号。

在获得最长非降子序列的长度后,不断查找表pre即可找到整个序列。(pre 初始化为-1,表示序列的头)

 

public class LIS{

    public static String getMaxLen(int[] a){
        //return the length of longest increasing subsequence and the subsequence
        int[] ml = new int[a.length];
        int[] pre = new int[a.length];
        //build length table
        for(int i = 0; i < ml.length; i ++){
            ml[i] = 1;
            pre[i] = -1;
            for(int j = 0; j < i; j ++){
                if(a[j] <= a[i] && ml[j] + 1 > ml[i]){
                    ml[i] = ml[j] + 1;
                    pre[i] = j;
                }
            }
        }
        //find max length
        int k = 0;
        for(int i = 1; i < ml.length; i ++){
            if(ml[k] < ml[i]){
                k = i;
            }
        }
        String result = Integer.toString(ml[k]);
        String temp = "";
        //get subsequence
        while(k != -1){
            temp = Integer.toString(a[k]) + " " + temp;
            k = pre[k];
        }
        result += "/" + temp;
        return result;
    }

    public static void main(String[] args) {
        int[] a = {5, 3, 4, 9, 6, 8};
        String[] result = getMaxLen(a).split("/");
        System.out.println(result[0]);
        System.out.println(result[1]);
    }
    
}
Java

 

posted @ 2013-11-27 16:31  7hat  阅读(772)  评论(0编辑  收藏  举报