《JAVA》中利用《動態規劃》實現《最小公共子序列》

動態規劃:遞歸導致的問題,很多小問題重複出現,所以有了動態規劃算法,讓許多小問題可以重複利用,減少算法的重複計算。

窮舉法
可使用窮舉法求解字符串A和B的最長公共子序列長度,算法描述如下:
列舉字符串A的除空串之外的所有子序列,設A的長度爲n,A共有2n-1個子序列。
例A=”abcd”,可能的24-1=15個子序列爲:
a、b、c、d、(4個)
ab、ac、ad、bc、bd、cd、(6個)
abc、abd、acd、bcd、(4個)
abcd (1個)

動態規劃法
設A=a1a2…an、B=b1b2…bm,L[i,j]表示a1a2…ai和b1b2…bj的最長公共子序列長度,很容易證明下面的觀察結論:
如果i和j都大於0,那麼
若ai=bj,a1…a(i-1)和b1…b(j-1)的最長子序列 + 1
L[i,j]=L[i-1,j-1]+1;
若ai≠bj,求取a1….ai和b1…b(j-1)的最長子序列
求取a1…a(i-1)和b1…b(j)的最長子序列
然後求取二者的最大值,即
L[i,j]=max(L[i,j-1],L[i-1,j])。

動態規劃實現 推導公式:

這裏寫圖片描述

算法分析:
這裏寫圖片描述

動態規劃特點:自下往上求解小問題

動態規劃法求解最長公共子序列。對於每對i和j的值,用一個二維數組L[0..m,0..n]來存放L[i,j]的值。
⑴設字符串A=a1a2…an,字符串B=b1b2…bm。以字符串A爲y軸,字符串B爲x軸。
⑵首先從A子串只有一個字符開始,計算出a1和B中各子串的最大公共子序列長度;然後逐個增加A子串中的字符,分別計算出當前A子串和B各子串的最大公共子序列長度;直至A的全部字符。
⑶L[i,j]表示A子串a1a2…ai(1≤i≤n)和B子串b1b2…bj(1≤j≤m)的最大公共子序列長度。
1. if ai=bj then
2. L[i,j]←L[i-1,j-1]+1
3. else
4. L[i,j]←max{L[i,j-1],L[i-1,j]}
5. end if

算法僞代碼:
輸入:字符串A和B,設A和B的長度分別爲n和m。
輸出:A和B的最長公共子序列的長度
1. for i←0 to n //字符串A爲y軸
2. L[i,0]←0 //字符串B爲空
3. end for
4. for j←0 to m //字符串B爲x軸
5. L[0,j]←0 //字符串A爲空
6. end for
7. for i←1 to n //A子串中字符逐個增加
8. for j←1 to m //當A子串確定,B子串中字符逐個增加。
9. if ai=bj then L[i,j]←L[i-1,j-1]+1 //i-1表示上一行
10. else L[i,j]←max{L[i,j-1],L[i-1,j]} //j-1表示前一列
11. end if
12. end for
13. end for
14. return L[m,n] //返回最長公共子序列長度

算法方法
這裏寫圖片描述
這裏寫圖片描述

算法具體實現:

package Test5;

/**
 * 最大公共子序列
 * 
 * @author Mr.洛洛
 * @by 2015.12.20
 */
public class LCS {
    static String strA = "zxyxyx";
    static String strB = "xyyzx";

    public static void main(String args[]) {
        int[][] arrs = new int[strA.length() + 1][strB.length() + 1];
        int maxLCSLength = LCSLength(arrs);
        printLCS(arrs);
        System.out.println("\n\t最長公共子序列長度爲:" + maxLCSLength);
    }

    /**
     * 最長公共子序列算法實現
     * 
     * @param arrs
     */
    public static int LCSLength(int[][] arrs) {
        for (int i = 0; i < arrs.length; i++) {
            System.out.println("==================最長公共子序列算法===================");
            System.out.println("\n======================第 " + (i + 1)
                    + " 次循環======================");
            if (i > 0) {
                System.out.println("strA = " + strA.substring(0, i)
                        + " , strB = ' " + strB + " '");
            } else {
                System.out.println("strA = 空 " + ", strB = " + strB);
            }
            for (int j = 0; j < arrs[i].length; j++) {
                if (i == 0 || j == 0) { // 若i=0 或 j=0
                    arrs[i][j] = 0;
                    System.out.println("arrs[" + i + "][" + j + "] = 0");
                } else {
                    if (i > 0 && j > 0
                            && (strA.charAt(i - 1) == strB.charAt(j - 1))) {     // 若i>0, j>0, 且ai = bj
                        arrs[i][j] = arrs[i - 1][j - 1] + 1;
                        System.out.println("arrs[" + i + "][" + j
                                + "] = arrs[i-1][j-1] + 1 = arrs[" + (i - 1)
                                + "][" + (j - 1) + "] + 1 = " + arrs[i][j]);
                    }
                    if (i > 0 && j > 0
                            && (strA.charAt(i - 1) != strB.charAt(j - 1))) {    // 若i>0, j>0,且ai != bj
                        arrs[i][j] = MaxNum(arrs[i][j - 1], arrs[i - 1][j]);
                        System.out
                                .println("arrs["
                                        + i
                                        + "]["
                                        + j
                                        + "] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs["
                                        + (i) + "][" + (j - 1) + "],  arrs["
                                        + (i - 1) + "][" + (j) + "]} = max{"
                                        + arrs[i][j - 1] + ",  "
                                        + arrs[i - 1][j] + "} = " + arrs[i][j]);
                    }
                }
            }
        }
        return arrs[strA.length()][strB.length()];
    }

    /**
     * 打印數組
     * 
     * @param arrs
     */
    public static void printLCS(int[][] arrs) {
        System.out.println("===========最後結果===========");
        for (int i = 0; i < arrs.length; i++) {
            for (int j = 0; j < arrs[i].length; j++) {
                System.out.print("\t" + arrs[i][j]);
            }
            System.out.println();
        }
    }

    /**
     * 比較兩個數的較大值
     * 
     * @param num1
     * @param num2
     * @return
     */
    public static int MaxNum(int num1, int num2) {
        return num1 > num2 ? num1 : num2;
    }
}

打印過程:

======================第 1 次循環======================
strA = 空 , strB = xyyzx
arrs[0][0] = 0
arrs[0][1] = 0
arrs[0][2] = 0
arrs[0][3] = 0
arrs[0][4] = 0
arrs[0][5] = 0

======================第 2 次循環======================
strA = z , strB = 'xyyzx'
arrs[1][0] = 0
arrs[1][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][0],  arrs[0][1]} = max{0,  0} = 0
arrs[1][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][1],  arrs[0][2]} = max{0,  0} = 0
arrs[1][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][2],  arrs[0][3]} = max{0,  0} = 0
arrs[1][4] = arrs[i-1][j-1] + 1 = arrs[0][3] + 1 = 1
arrs[1][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][4],  arrs[0][5]} = max{1,  0} = 1

======================第 3 次循環======================
strA = zx , strB = 'xyyzx'
arrs[2][0] = 0
arrs[2][1] = arrs[i-1][j-1] + 1 = arrs[1][0] + 1 = 1
arrs[2][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][1],  arrs[1][2]} = max{1,  0} = 1
arrs[2][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][2],  arrs[1][3]} = max{1,  0} = 1
arrs[2][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][3],  arrs[1][4]} = max{1,  1} = 1
arrs[2][5] = arrs[i-1][j-1] + 1 = arrs[1][4] + 1 = 2

======================第 4 次循環======================
strA = zxy , strB = 'xyyzx'
arrs[3][0] = 0
arrs[3][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][0],  arrs[2][1]} = max{0,  1} = 1
arrs[3][2] = arrs[i-1][j-1] + 1 = arrs[2][1] + 1 = 2
arrs[3][3] = arrs[i-1][j-1] + 1 = arrs[2][2] + 1 = 2
arrs[3][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][3],  arrs[2][4]} = max{2,  1} = 2
arrs[3][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][4],  arrs[2][5]} = max{2,  2} = 2

======================第 5 次循環======================
strA = zxyx , strB = 'xyyzx'
arrs[4][0] = 0
arrs[4][1] = arrs[i-1][j-1] + 1 = arrs[3][0] + 1 = 1
arrs[4][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][1],  arrs[3][2]} = max{1,  2} = 2
arrs[4][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][2],  arrs[3][3]} = max{2,  2} = 2
arrs[4][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][3],  arrs[3][4]} = max{2,  2} = 2
arrs[4][5] = arrs[i-1][j-1] + 1 = arrs[3][4] + 1 = 3

======================第 6 次循環======================
strA = zxyxy , strB = 'xyyzx'
arrs[5][0] = 0
arrs[5][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][0],  arrs[4][1]} = max{0,  1} = 1
arrs[5][2] = arrs[i-1][j-1] + 1 = arrs[4][1] + 1 = 2
arrs[5][3] = arrs[i-1][j-1] + 1 = arrs[4][2] + 1 = 3
arrs[5][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][3],  arrs[4][4]} = max{3,  2} = 3
arrs[5][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][4],  arrs[4][5]} = max{3,  3} = 3

======================第 7 次循環======================
strA = zxyxyx , strB = 'xyyzx'
arrs[6][0] = 0
arrs[6][1] = arrs[i-1][j-1] + 1 = arrs[5][0] + 1 = 1
arrs[6][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][1],  arrs[5][2]} = max{1,  2} = 2
arrs[6][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][2],  arrs[5][3]} = max{2,  3} = 3
arrs[6][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][3],  arrs[5][4]} = max{3,  3} = 3
arrs[6][5] = arrs[i-1][j-1] + 1 = arrs[5][4] + 1 = 4

===========最後結果===========
    0   0   0   0   0   0
    0   0   0   0   1   1
    0   1   1   1   1   2
    0   1   2   2   2   2
    0   1   2   2   2   3
    0   1   2   3   3   3
    0   1   2   3   3   4
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章