動態規劃實例(十三):最長公共子串(LCS)

    最長公共子序列 & 最長公共子串的區別:找兩個字符串的最長公共子串,這個子串要求在原字符串中是連續的。而最長公共子序列則並不要求連續
    這兩個都可以使用動態規劃解決,但是思路不太一樣。
    我們採用一個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧:”bab”和”caba”(當然我們現在一眼就可以看出來最長公共子串是”ba”或”ab”)
             b  a  b
         c  0  0  0
         a  0  1  0
         b  1  0  1
         a  0  1  0
    我們看矩陣的斜對角線最長的那個就能找出最長公共子串。不過在二維矩陣上找最長的由1組成的斜對角線也是件麻煩費時的事,下面改進:當要在矩陣是填1時讓它等於其左上角元素加1。
             b  a  b
         c  0  0  0
         a  0  1  0
         b  1  0  2
         a  0  2  0

這樣矩陣中的最大元素就是 最長公共子串的長度。

具體實例及實現代碼如下所示:

/**
 * @Title: LongestCommomSubString.java
 * @Package dynamicprogramming
 * @Description: TODO
 * @author peidong
 * @date 2017-6-13 上午8:41:48
 * @version V1.0
 */
package dynamicprogramming;

/**
 * @ClassName: LongestCommomSubString
 * @Description:最長公共子串
 * @date 2017-6-13 上午8:41:48
 *
 */
public class LongestCommomSubString {

    /**
     *
     * @Title: longestCommonSubString
     * @Description: 動態規劃求解最長公共子串
     * @param str1
     * @param str2
     * @return
     * @return String
     * @throws
     */
    public static String longestCommonSubString(String str1, String str2){
        //創建變量保存公共子串,此處不能用String,需要改變
        StringBuilder sb = new StringBuilder();
        //邊界條件判斷
        if(str1 == null || str1.isEmpty() || str2 == null || str2.isEmpty())
            return "";

        //創建狀態轉移矩陣,保存子串長度
        int[][] tc = new int[str1.length()][str2.length()];
        //定義變量保存最長字符串長度
        int maxLen = 0;
        //定義變量保存最長子串起始位置
        int lastSubsBegin = 0;

        //構建狀態轉移矩陣
        for(int i = 0; i < str1.length(); i++){
            for(int j = 0; j < str2.length(); j++){
                if(str1.charAt(i) == str2.charAt(j)){
                    if(i == 0 || j == 0)
                        tc[i][j] = 1;
                    else
                        tc[i][j] = 1 + tc[i-1][j-1];
                    if(tc[i][j] > maxLen){
                        maxLen = tc[i][j];

                        //記錄此時子串在str1中的起始位置
                        int thisBegin = i - tc[i][j] + 1;
                        //如果是同一個子串
                        if(lastSubsBegin == thisBegin)
                            sb.append(str1.charAt(i));
                        else{//不是同一個子串重新生成
                            lastSubsBegin = thisBegin;
                            sb = new StringBuilder();
                            sb.append(str1.substring(lastSubsBegin, i + 1));
                        }
                    }
                }
            }
        }
        return sb.toString();
    }
    /**
     * @Title: main
     * @Description: 測試用例
     * @param args
     * @return void
     * @throws
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String str1 = "I love python!";
        String str2 = "love python I do";
        String str = longestCommonSubString(str1, str2);
        System.out.println("兩字符串的最長公共子串爲:" + str);
        System.out.println("最長公共子串的長度爲:" + str.length());
    }

}


發佈了110 篇原創文章 · 獲贊 65 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章