1143 最長公共子串行

2021-10-03 04:41:18 字數 3631 閱讀 9659

給定兩個字串 text1 和 text2,返回這兩個字串的最長公共子串行。

乙個字串的 子串行 是指這樣乙個新的字串:它是由原字串在不改變字元的相對順序的情況下刪除某些字元(也可以不刪除任何字元)後組成的新字串。

例如,「ace」 是 「abcde」 的子串行,但 「aec」 不是 「abcde」 的子串行。兩個字串的「公共子串行」是這兩個字串所共同擁有的子串行。

若這兩個字串沒有公共子串行,則返回 0。

示例 1:

輸入:text1 = "abcde", text2 = "ace" 

輸出:3

解釋:最長公共子串行是 "ace",它的長度為 3。

示例 2:

輸入:text1 = "abc", text2 = "abc"

輸出:3

解釋:最長公共子串行是 "abc",它的長度為 3。

示例 3:

輸入:text1 = "abc", text2 = "def"

輸出:0

解釋:兩個字串沒有公共子串行,返回 0。

1 <= text1.length <= 1000

1 <= text2.length <= 1000

輸入的字串只含有小寫英文本元。

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

題目就是讓我們求兩個字串的 lcs 長度。

肯定有讀者會問,為啥這個問題就是動態規劃來解決呢?因為子串行型別的問題,窮舉出所有可能的結果都不容易,而動態規劃演算法做的就是窮舉 + 剪枝,它倆天生一對兒。所以可以說只要涉及子串行問題,十有**都需要動態規劃來解決,往這方面考慮就對了。

下面就來手把手分析一下,這道題目如何用動態規劃技巧解決。

第一步,一定要明確dp陣列的含義。對於兩個字串的動態規劃問題,套路是通用的。

比如說對於字串s1s2,一般來說都要構造乙個這樣的 dp table:

為了方便理解此表,我們暫時認為索引是從 1 開始的,待會的**中只要稍作調整即可。其中,dp[i][j]的含義是:對於s1[1..i]s2[1..j],它們的 lcs 長度是dp[i][j]

比如上圖的例子,d[2][4]的含義就是:對於"ac""babc",它們的 lcs 長度是 2。我們最終想得到的答案應該是dp[3][6]

第二步,定義 base case。

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

比如說,按照剛才 dp 陣列的定義,dp[0][3]=0的含義是:對於字串"""bab",其 lcs 的長度為 0。因為有乙個字串是空串,它們的最長公共子串行的長度顯然應該是 0。

第三步,找狀態轉移方程。

這是動態規劃最難的一步,不過好在這種字串問題的套路都差不多,權且借這道題來聊聊處理這類問題的思路。

狀態轉移說簡單些就是做選擇,比如說這個問題,是求s1s2的最長公共子串行,不妨稱這個子串行為 lcs。那麼對於s1s2中的每個字元,有什麼選擇?很簡單,兩種選擇,要麼在lcs中,要麼不在。

這個「在」和「不在」就是選擇,關鍵是,應該如何選擇呢?這個需要動點腦筋:如果某個字元應該在lcs中,那麼這個字元肯定同時存在於s1s2中,因為lcs是最長公共子串行嘛。所以本題的思路是這樣:

用兩個指標ij從後往前遍歷s1s2,如果s1[i]==s2[j],那麼這個字元一定在lcs中;否則的話,s1[i]s2[j]這兩個字元至少有乙個不在lcs中,需要丟棄乙個。先看一下遞迴解法,比較容易理解:

def longestcommonsubsequence

(str1, str2)

->

int:

def dp

(i, j)

: # 空串的 base case

if i ==

-1 or j ==-1

:return

0if str1[i]

== str2[j]

: # 這邊找到乙個 lcs 的元素,繼續往前找

return

dp(i -

1, j -1)

+1else

: # 誰能讓 lcs 最長,就聽誰的

return

max(

dp(i-

1, j),dp

(i, j-1)

) # i 和 j 初始化為最後乙個索引

returndp(

len(str1)-1

,len

(str2)-1

)

對於第一種情況,找到乙個lcs中的字元,同時將ij向前移動一位,並給 lcs 的長度加一;對於後者,則嘗試兩種情況,取更大的結果。

其實這段**就是暴力解法,我們可以通過備忘錄或者 dp table 來優化時間複雜度,比如通過前文描述的 dp table 來解決:

class

solution

return dp[len1]

[len2];}

}

對於兩個字串的動態規劃問題,一般來說都是像本文一樣定義 dp table,因為這樣定義有乙個好處,就是容易寫出狀態轉移方程,dp[i][j]的狀態可以通過之前的狀態推導出來:

找狀態轉移方程的方法是,思考每個狀態有哪些「選擇」,只要我們能用正確的邏輯做出正確的選擇,演算法就能夠正確執行。

1143 最長公共子串行

給定兩個字串 text1 和 text2,返回這兩個字串的最長公共子串行。乙個字串的 子串行 是指這樣乙個新的字串 它是由原字串在不改變字元的相對順序的情況下刪除某些字元 也可以不刪除任何字元 後組成的新字串。例如,ace 是 abcde 的子串行,但 aec 不是 abcde 的子串行。兩個字串的...

1143 最長公共子串行

一.題目描述 二.動態規劃解法 例如 s1 abcde s2 ace 求兩個字串的公共子串行,答案是 ace 1.s t 2.子問題劃分 1 如果s的最後一位等於t的最後一位,則最大子串行就是和的最大子串行 1 2 如果s的最後一位不等於t的最後一位,那麼最大子串行就是 和 最大子串行 和 最大子串...

1143 最長公共子串行

給定兩個字串 text1 和 text2,返回這兩個字串的最長公共子串行的長度。乙個字串的 子串行 是指這樣乙個新的字串 它是由原字串在不改變字元的相對順序的情況下刪除某些字元 也可以不刪除任何字元 後組成的新字串。例如,ace 是 abcde 的子串行,但 aec 不是 abcde 的子串行。兩個...