動態規劃---實現輸出最大公用子序列的長度以及輸出最大子字串(java語言描述)

來源:互聯網
上載者:User

參考部落格地址:http://blog.csdn.NET/biangren/article/details/8038605

http://blog.csdn.net/njr465167967/article/details/51675424 動態規劃法        分治法是指將問題劃分成一些獨立的子問題,遞迴地求解各子問題,然後合并子問題的解而得到原問題的解。然而經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題,也就是各子問題包含公用的子子問題。若簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。動態規劃方法對每個子子問題只求解一次,將其結果儲存在一張表中,從【問題】 求兩字元序列的最長公用字元子序列

問題描述:字元序列的子序列是指從給定字元序列中隨意地(不一定連續)去掉若干個字元(可能一個也不去掉)後所形成的字元序列。令給定的字元序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一個嚴格遞增下標序列<i0,i1,…,ik-1>,使得對所有的j=0,1,…,k-1,有xij=yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一個子序列。

考慮最長公用子序列問題如何分解成子問題,設A=“a0,a1,…,am-1”,B=“b0,b1,…,bm-1”,並Z=“z0,z1,…,zk-1”為它們的最長公用子序列。不難證明有以下性質:

(1) 如果am-1=bn-1,則zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一個最長公用子序列;

(2) 如果am-1!=bn-1,則若zk-1!=am-1,意味著“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一個最長公用子序列;

(3) 如果am-1!=bn-1,則若zk-1!=bn-1,意味著“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一個最長公用子序列。

       這樣,在找A和B的公用子序列時,如有am-1=bn-1,則進一步解決一個子問題,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一個最長公用子序列;如果am-1!=bn-1,則要解決兩個子問題,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一個最長公用子序列和找出“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一個最長公用子序列,再取兩者中較長者作為A和B的最長公用子序列。而避免每次遇到各個子問題時重新計算答案。
求解:

引進一個二維數組c[][],用c[i][j]記錄X[i]與Y[j] 的LCS 的長度,b[i][j]記錄c[i][j]是通過哪一個子問題的值求得的,以決定搜尋的方向。
我們是自底向上進行遞推計算,那麼在計算c[i,j]之前,c[i-1][j-1],c[i-1][j]與c[i][j-1]均已計算出來。此時我們根據X[i] = Y[j]還是X[i] != Y[j],就可以計算出c[i][j]。
問題的遞迴式寫成:
回溯輸出最長公用子序列過程: 演算法分析:
       由於每次調用至少向上或向左(或向上向左同時)移動一步,故最多調用(m + n)次就會遇到i = 0或j = 0的情況,此時開始返回。返回時與遞迴調用時方向相反,步數相同,故演算法時間複雜度為Θ(m +n)。
Java實現代碼如下:

package com.hbut.test;/** * Created by HP on 2017/6/6. */public class LCS {    public static void main(String[] args) {        String str1 = "ABCBDAB";        String str2 = "BDCABA";        System.out.println(getMaxSubstringLen(str1, str2));        int[][] b = getTrace(str1, str2);        String sMax = str1.length() > str2.length() ? str1 : str2; // 選擇最長的串,因為要取出最大子串        String sMin = str1.length() < str2.length() ? str1 : str2; // 選擇最小的串        print(b, sMax, sMax.length(), sMin.length());    }    public static int getMaxSubstringLen(String x, String y) {        int xLen = x.length() + 1;                  //加1是因為初始化第一個為0        int yLen = y.length() + 1;        int rLen = xLen > yLen ? xLen : yLen;       //大的串置為行        int cLen = xLen < yLen ? xLen : yLen;       //小的串置為列        int[][] c = new int[rLen][cLen];            //矩陣c儲存狀態        for (int i = 1; i < rLen; i++) {            for (int j = 1; j < cLen; j++) {                if (x.charAt(i - 1) == y.charAt(j - 1)) {   //相等,由斜對角線+1                    c[i][j] = c[i - 1][j - 1] + 1;                } else if (c[i - 1][j] >= c[i][j - 1]) {    //不相等,選取較大的                    c[i][j] = c[i - 1][j];                } else {                    c[i][j] = c[i][j - 1];                }            }        }        return c[xLen - 1][yLen - 1];               //最後那個就是最長的公用序列數量    }    //記錄值的狀態,便於後面回溯    public static int[][] getTrace(String x, String y) {        int xLen = x.length() + 1;        int yLen = y.length() + 1;        int rLen = xLen > yLen ? xLen : yLen;        int cLen = xLen < yLen ? xLen : yLen;        int[][] c = new int[rLen][cLen];        int[][] b = new int[rLen][cLen];        for (int i = 1; i < rLen; i++) {            for (int j = 1; j < cLen; j++) {                if (x.charAt(i - 1) == y.charAt(j - 1)) {                    c[i][j] = c[i - 1][j - 1] + 1;                    b[i][j] = 2;                } else if (c[i - 1][j] >= c[i][j - 1]) {                    c[i][j] = c[i - 1][j];                    b[i][j] = -1;                } else {                    c[i][j] = c[i][j - 1];                    b[i][j] = 0;                }            }        }        return b;    }    // 遞迴實現回溯,然後列印出最長公用子序列(不連續子序列)    public static void print(int[][] b, String s, int i, int j) {        // 遞迴終止條件        if (i == 0 || j == 0) {            return;        }        if (b[i][j] == 2) {            print(b, s, i - 1, j - 1);            System.out.print(s.charAt(i - 1) + " ");        } else if (b[i][j] == -1) {            print(b, s, i - 1, j);        } else if (b[i][j] == 0) {            print(b, s, i, j - 1);        }    }}

輸出結果: 4
B C B A 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.