動態規劃7:最長上升子序列LIS

LingLee_荊棘鳥發表於2017-07-18

題目:這是一個經典的LIS(即最長上升子序列)問題,請設計一個儘量優的解法求出序列的最長上升子序列的長度。給定一個序列A及它的長度n(長度小於等於500),請返回LIS的長度。


樣例:[1,4,2,5,3],5返回:3


思路:從前向後求出以index為終點的序列的最長遞增子序列長度:

注意子序列並不要求連續,即子序列不等於連續子序列。例如1,4,2,5,3,8,6,9。裡面的遞增子序列有很多,1,4是遞增子序列,1,4,5,8,9是遞增子序列,4,5,8,9是遞增子序列,4,5,6,9是遞增子序列。

對於最長子序列,前面不應該有更小的元素,後面不應該有更大的元素。例如1,4,2,5然後考慮把3加上去後會最長遞增子序列會發生怎樣的變化,3加上後與前面比3更小的元素2構成了子序列,即對於以2為終點的序列,加上3後使得序列右增加了1,且此時序列的終點變成了3。於是思路是:

Index=0時maxLength=1;   【1】

Index=1時maxLength=2;  【1,4】

Index=2時maxLength=2;  【1,2】

Index=3時maxLength=3;  【1,4,5】【1,2,5】

Index=4時maxLength=3;  【1,2,3】

Index=5時maxLength=4;  【1,4,5,8】【1,2,5,8】【1,2,3,8】

Index=6時maxLength=4;  【1,4,5,6】【1,2,5,6】【1,2,3,6】

Index=7時maxLength=5;  【1,4,5,8,9】【1,2,5,8,9】【1,2,3,8,9】【1,4,5,6,9】【1,2,5,6,9】【1,2,3,6,9】

對於index,在求它的最長遞增子序列時是先將arr[index]與之前的元素進行逐一比較,找出小於arr[index]的元素中maxLength最長的值,於是對於元素index,以它為終點的最長遞增子序列長度就是在maxLength上+1,並將此結果儲存在一個陣列dp[index]中以便後面複用。

即從index=0開始逐一計算以arr[index]為最長遞增序列終點的最長遞增子序列長度,將其儲存在dp[index]中,在計算後面任意一個index為終點的最長遞增序列長度時,遍歷前面的所有元素的maxLength,找出元素arr[i]<arr[index]的元素中的最大的maxLength值,將arr[index]加在這個序列上構成以arr[index]為終點的最長遞增子序列,以此類推,當index到達結尾時所有子序列長度遍歷結束,掃描整個陣列dp[]裡面的最大值就是最大遞增子序列的長度(最後一個元素index並不一定是最長子序列的終點元素,即可能最長遞增子序列 在一個序列的中間位置)

動態規劃:

①建立動態規劃陣列保留每個計算結果,這裡只需要一維陣列dp[n];

②先計算dp[]中第一個位置的值,即dp[0],即以arr[0]為終點的最長遞增子序列的最大子序列長度是1;

③從前往後計算dp[]中的每一個位置的值;注意遞推關係的使用;

④掃描dp[],裡面的最大值就是所求結果;

public class LongestIncreasingSubsequence {
    public int getLIS(int[] A, int n) {
        // write code here
        if (A == null)
            return 0;
        int[] dp = new int[n];
        dp[0] = 1;
        int top = 0;
        for (int i = 1; i < n; ++i) {
            int max = 0;
            for (int j = i - 1; j >= 0; --j) {
                if (max < dp[j] && A[j] < A[i])
                    max = dp[j];
            }
            dp[i] = max + 1;
            if (top < dp[i])
                top = dp[i];
        }
        return top;
    }
}



相關文章