這兩個都可以使用動態規劃解決,但是思路不太一樣。
我們採用一個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧:”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()); } }