- 最長子序列:匹配的字符不需要連續。
- 最長子串: 匹配的字符需要連續,可能有多種結果。
解決思路:將輸入字符串1看作行, 輸入字符串2看作列,構成二位數組,然后將對角線匹配字符的值標記為1,計算滿足條件的匹配字符個數即可。
基本思想: 空間換時間,動態規划。
圖解與公式(只針對最長子序列,最長子串類似)

狀態轉移方程

直觀版:
最長子序列
1 /** 2 * find longest common sequence from two input string 3 * @param s1 4 * @param s2 5 * @return length of longest common sequence 6 */ 7 public static int LCS(String s1, String s2) { 8 int[][] c = new int[s1.length()][s2.length()]; 9 10 // initialize the elements without top left element 11 for(int i=0; i<s1.length();i++){ 12 if (s1.charAt(i) == s2.charAt(0)) { 13 c[i][0] = 1; 14 } 15 } 16 for(int j = 0; j<s2.length();j++){ 17 if (s1.charAt(0) == s2.charAt(j)) { 18 c[0][j] = 1; 19 } 20 } 21 for (int i = 1; i < s1.length(); i++) { 22 for (int j = 1; j < s2.length(); j++) { 23 if (s1.charAt(i) == s2.charAt(j)) { 24 c[i][j] = c[i - 1][j - 1] + 1; 25 } else if (c[i][j - 1] > c[i - 1][j]) { 26 c[i][j] = c[i][j - 1]; 27 } else { 28 c[i][j] = c[i - 1][j]; 29 } 30 } 31 } 32 return c[s1.length() - 1][s2.length() - 1]; 33 }
最長子序列也可以用穩定的排序算法先排序,再匹配。如采用歸並排序算法(注意,快速排序不穩定)。
最長子串
1 /** 2 * find longest substring from two input string 3 * 4 * @param s1 5 * @param s2 6 * @return length of longest substring 7 */ 8 public static int LSS(String s1, String s2) { 9 int[][] c = new int[s1.length()][s2.length()]; 10 int max = 0; 11 12 // initialize the elements without top left element 13 for(int i=0; i<s1.length();i++){ 14 if (s1.charAt(i) == s2.charAt(0)) { 15 c[i][0] = 1; 16 } 17 } 18 for(int j = 0; j<s2.length();j++){ 19 if (s1.charAt(0) == s2.charAt(j)) { 20 c[0][j] = 1; 21 } 22 } 23 24 for (int i = 1; i < s1.length(); i++) { 25 for (int j = 1; j < s2.length(); j++) { 26 if (s1.charAt(i) == s2.charAt(j)) { 27 c[i][j] = c[i - 1][j - 1] + 1; 28 if (c[i][j] > max) { 29 max = c[i][j]; 30 } 31 } 32 } 33 } 34 return max; 35 }
優化版:
待續..
優化基本思想:
可以采用遞歸方式,盡早舍棄不符合要求的匹配。
對於優化最長子串,
可以優先查找最長子串,如果發現一個匹配,就一直找下去,同時將最終的不匹配標記為-1而不是0.
如果剩余的可能匹配長度小於已找到的長度,則停止遞歸操作,直接return.
其他相關算法
