動態規劃問題(六)最長公共子序列(LCS)
阿新 • • 發佈:2021-08-15
動態規劃問題(六)最長公共子序列(LCS)
問題描述
給你兩個字串,要求得到這兩個字串的最長公共子序列長度。
比如:對於輸入的字串 S1 "AGGTAB" 和 S2 "GXTXAYB",它們的最長公共子序列長度為 4,為 {'G', 'T', 'A', 'B'}
解決思路
該問題剛開始見到時沒有思路,但是把問題細分一下找到規律即可解決。
-
遞迴
-
對於當前輸入的兩個字串,可以通過不斷將兩個字串的分別移除來減小問題的規模,最終收斂
-
以上文的輸入為例,對於輸入的 S1 “AGGTAB” 和 S2 “GXTXAYB”,首先將 S1 的第一個字元與 S2 的第一個字元比較,然後移除 S1 的第一個字元再與 S2進行比較…… 對 S2 做同樣的操作。此時的情況如下圖所示:
-
-
動態規劃
- 動態規劃在這裡的解決的是重複子問題的型別,由於上文的遞迴方案,在這個解決過沖中存在大量的重複計算,因此可以使用動態規劃儲存中間計算結果,從而提高執行效率。
實現
-
遞迴
public class Solution { public static int lcs(String s1, String s2) { int len1 = s1.length(), len2 = s2.length(); // 遞迴終止條件 if (len1 == 1 || len2 == 1) return s1.charAt(0) == s2.charAt(0) ? 1 : 0; // 遞迴剩下的結果得到該問題的解 if (s1.charAt(0) == s2.charAt(0)) return Math.max( lcsRecur(s1.substring(1), s2), lcsRecur(s1, s2.substring(1)) ) + 1; return Math.max( lcsRecur(s1.substring(1), s2), lcsRecur(s1, s2.substring(1)) ); } }
-
動態規劃
public class Solution { public static int lcs(String s1, String s2) { // 將字串轉變為對應的字元陣列,提高查詢的速度 char[] s1Arr = s1.toCharArray(); char[] s2Arr = s2.toCharArray(); int row = s1Arr.length, col = s2Arr.length; // 儲存中間計算結果的二維陣列 int[][] dp = new int[row + 1][col + 1]; for (int i = 1; i <= row; ++i) { for (int j = 1; j <= col; ++j) { if (s1Arr[i - 1] == s2Arr[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; // 由於要保證當前的字元是在之前比較的字元之後的,因此需要得到的是左上角的元素中間值 else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } return dp[row][col]; } }