字串的最長公共子串行

2021-10-23 14:49:40 字數 1678 閱讀 2210

審題

最長公共子串行(longest common subsequence,簡稱 lcs)是一道非常經典的面試題目,因為它的解法是典型的二維動態規劃,大部分比較困難的字串問題都和這個問題乙個套路,比如說編輯距離。而且,這個演算法稍加改造就可以用於解決其他問題,所以說lcs演算法是值得掌握的。

所謂子串行,就是要保留原始順序,但可以是不連續的。審題之後你可能會有疑問,這個問題為啥就是動態規劃來解決呢?因為子串行型別的問題,窮舉出所有可能的結果都不容易,而動態規劃演算法做的就是窮舉 + 剪枝,它倆天生一對兒。所以可以說只要涉及子串行問題,十有**都需要動態規劃來解決。

動態規劃思路

第一步,一定要明確 dp 陣列的含義。

對於兩個字串的動態規劃問題,套路是通用的。

比如說對於字串 s1 和 s2,它們的長度分別是 m、n,一般來說都要構造乙個這樣的 dp table:int dp = new int[m+1][n+1]。

這裡為什麼要加1,原因是你可以不加1,但是不加1你就會用其它限制條件來確保這個index是有效的,而當你加1之後你就不需要去判斷只是讓索引為0的行和列表示空串。

第二步,定義 base case

我們專門讓索引為0的行和列表示空串,dp[0][…] 和 dp[…][0] 都應該初始化為0,這就是base case。

第三部,找狀態轉移方程

這是動態規劃最難的一步,我們來通過案例推導出來。

對於 text1:abcde 和 text2:ace 兩個字串,我們定義兩個指標進行遍歷 i 和 j。

遍歷 text1 長度為 m,定義指標 i,從 0~m。固定 i 指標(i == 1)位置,接下來開始遍歷 text2 長度為 n,定義指標 j,從 0~n。

第一次遍歷 i = 1, j = 1,兩個a相同所以 dp[1][1] = 1

第二次遍歷 i = 1, j = 2,a與c不等,也不能是0,這裡需轉換成 a 與 ac 最長子序列,這裡需要把之前的關係傳遞過來,所以dp[1][2] = 1

第三次遍歷 i = 1, j = 3,a與e不相同,把之前的關係傳遞過來,所以dp[1][3] = 1

text2:ace 已經走完來第一輪,接下來text1:abcde 走到來b字元。

第四次遍歷 i = 2, j = 1,就是需要比較ab與a的最長子串,把之前的關係傳遞過來,所以dp[2][1] = 1

依次類推…(詳看上圖)

我們會發現遍歷兩個串字元,當不同時需要考慮兩層遍歷前面的值(關係傳遞),也就是左邊和上邊的其中較大的值,當想相同時,需要考慮各自不包含當前字串的子串行長度,再加上1。

因此可以得出:

現在對比的這兩個字元不相同的,那麼我們要取它的「要麼是text1往前退一格,要麼是text2往前退一格,兩個的最大值」

dp[i + 1][j + 1] = math.max(dp[i+1][j], dp[i][j+1]);

對比的兩個字元相同,去找它們前面各退一格的值加1即可:dp[i+1][j+1] = dp[i][j] + 1;

參考**

class

solution

else}}

return dp[m]

[n];

}}

最長公共字串和最長公共子串行

給出兩個字串,找到最長公共子串,並返回其長度。建立乙個矩陣來儲存兩個字串出現相同字元的地方,比如 abccd 和 abcefc 就有 abccd a10000 b02000 c00300 e00040 f00000 c00100 這樣就有每次遇到相等的都加上下他的斜上方的位置的值,然後使用乙個max...

字串中最長公共子串行和最長公共子串

例 bdcaba和abcbdab,最長公共子串行為 bcba。dp解法 字串1的長度為length1,字串2的長度為length2,建立乙個二維陣列c length1 length2 用來記錄最長公共子串行的長度,狀態轉移方程為 整個狀態轉移以及二維陣列矩陣c為 生成字串長度加1的0矩陣,m用來儲存...

最長公共子串行 最長公共子串

1 最長公共子串行 採用動態規劃的思想,用乙個陣列dp i j 記錄a字串中i 1位置到b字串中j 1位置的最長公共子串行,若a i 1 b j 1 那麼dp i j dp i 1 j 1 1,若不相同,那麼dp i j 就是dp i 1 j 和dp i j 1 中的較大者。class lcs el...