1. 程式人生 > >【動態規劃】最長公共子序列與最長公共子串

【動態規劃】最長公共子序列與最長公共子串

1. 問題描述

子串應該比較好理解,至於什麼是子序列,這裡給出一個例子:有兩個母串

  • cnblogs
  • belong

比如序列bo, bg, lg在母串cnblogs與belong中都出現過並且出現順序與母串保持一致,我們將其稱為公共子序列。最長公共子序列(Longest Common Subsequence, LCS),顧名思義,是指在所有的子序列中最長的那一個。子串是要求更嚴格的一種子序列,要求在母串中連續地出現。在上述例子的中,最長公共子序列為blog(cnblogs, belong),最長公共子串為lo(cnblogs, belong)。

2. 求解演算法

對於母串\(X = < x_1, x_2, \cdots , x_m >\)

, \(Y = < y_1, y_2, \cdots , y_n >\),求LCS與最長公共子串。

暴力解法

假設 \(m < n\), 對於母串\(X\),我們可以暴力找出\(2^m\)個子序列,然後依次在母串\(Y\)中匹配,演算法的時間複雜度會達到指數級\(O(n*2^m)\)。顯然,暴力求解不太適用於此類問題。

動態規劃

假設\(Z =< z_1, z_2, \cdots , z_k >\)\(X\)\(Y\)的LCS, 我們觀察到

  • 如果\(x_m = y_n\),則\(z_k = x_m = y_n\),有\(Z_{k-1}\)\(X_{m-1}\)
    \(Y_{n-1}\)的LCS;
  • 如果\(x_m \ne y_n\),則\(Z_{k}\)\(X_{m}\)\(Y_{n-1}\)的LCS,或者是\(X_{m-1}\)\(Y_{n}\)的LCS。

因此,求解LCS的問題則變成遞迴求解的兩個子問題。但是,上述的遞迴求解的辦法中,重複的子問題多,效率低下。改進的辦法——用空間換時間,用陣列儲存中間狀態,方便後面的計算。這就是動態規劃(DP)的核心思想了。

DP求解LCS

用二維陣列c[i][j]記錄串\(x_1x_2 \cdots x_i\)\(y_1y_2\cdots y_j\)的LCS長度,則可得到狀態轉移方程
\[ c[i,j] = \left\{ {\matrix{ 0 & {{i = 0 \rm{\ or \ }j = 0}} \cr {c[i - 1,j - 1] + 1} & {{i, j > 0 \rm{\ and\ } \ }{{x}}_i} = {y_j} \cr {\max ({c[i, j - 1], c[i - 1, j])}} & {{i, j > 0 \rm{\ and\ }}{{\rm{x}}_i} \ne {y_j}} \cr } } \right. \]

程式碼實現

public static int lcs(String str1, String str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int c[][] = new int[len1+1][len2+1];
    for (int i = 0; i <= len1; i++) {
        for( int j = 0; j <= len2; j++) {
            if(i == 0 || j == 0) {
                c[i][j] = 0;
            } else if (str1.charAt(i-1) == str2.charAt(j-1)) {
                c[i][j] = c[i-1][j-1] + 1;
            } else {
                c[i][j] = max(c[i - 1][j], c[i][j - 1]);
            }
        }
    }
    return c[len1][len2];
}

DP求解最長公共子串

前面提到了子串是一種特殊的子序列,因此同樣可以用DP來解決。定義陣列的儲存含義對於後面推導轉移方程顯得尤為重要,糟糕的陣列定義會導致異常繁雜的轉移方程。考慮到子串的連續性,將二維陣列\(c[i,j]\)用來記錄具有這樣特點的子串——結尾為母串\(x_1x_2 \cdots x_i\)\(y_1y_2\cdots y_j\)的結尾——的長度。

得到轉移方程:
\[ c[i,j] = \left\{ {\matrix{ 0 & {i = 0 \rm{\ or\ }j = 0} \cr {c[i - 1,j - 1]+1} & {{x_i} = {y_j}} \cr 0 & {{x_i} \ne {y_j}} \cr } } \right. \]

最長公共子串的長度為 \(max(c[i,j]), \ i\in \lbrace 1,\cdots, m \rbrace, j\in \lbrace 1,\cdots,n \rbrace\)

程式碼實現

public static int lcs(String str1, String str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int result = 0;     //記錄最長公共子串長度
    int c[][] = new int[len1+1][len2+1];
    for (int i = 0; i <= len1; i++) {
        for( int j = 0; j <= len2; j++) {
            if(i == 0 || j == 0) {
                c[i][j] = 0;
            } else if (str1.charAt(i-1) == str2.charAt(j-1)) {
                c[i][j] = c[i-1][j-1] + 1;
                result = max(c[i][j], result);
            } else {
                c[i][j] = 0;
            }
        }
    }
    return result;
}

3. 參考資料

相關推薦

動態規劃LCS演算法:求兩字串公共字串(連續)

LCS演算法的應用 問題描述:求兩字串的連續最大公共子字串 思路:根據上文LCS演算法求解兩字串的最大公共子序列(不連續),可以得到求解連續子字串的啟示,如圖所示,構造LCS矩陣vec,將兩個字串按矩

動態規劃公共序列問題

clas == 搜索 ios for 參考 pan 公式 是否 題目描述: 給定兩個字符串s1s2……sn和t1t2……tn。求出這兩個字符串最長的公共子序列的長度。字符串s1s2……sn的子序列指可以表示為si1si2……sim(i1<i2<……<im)

動態規劃公共迴文

題目 : 給定兩個字串,求出它們之間連續的最長的相同子字串的長度。 eg : fbaabe,ebaabf,連續最長子串長度為4。 注意:求最長迴文子串也可以用求最長公共子串來求,只需將字串反轉作為另外一個字串,迴文部分反轉之後不變,然後求LCS(Longes

動態規劃公共序列公共

1. 問題描述 子串應該比較好理解,至於什麼是子序列,這裡給出一個例子:有兩個母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs與belong中都出現過並且出現順序與母串保持一致,我們將其稱為公共子序列。最長公共子序列(Longest Common Subsequence

動態規劃NYOJ公共序列

最長公共子序列 時間限制:3000 ms  |  記憶體限制:65535 KB 難度:3 描述咱們就不拐彎抹角了,如題,需要你做的就是寫一個程式,得出最長公共子序列。 tip:最長公共子序

動態規劃--無重複

給定一個字串,找出不含有重複字元的最長子串的長度。 示例: 給定 "abcabcbb" ,沒有重複字元的最長子串是 "abc" ,那麼長度就是3。 給定 "bbbbb" ,最長的子串就是 "b" ,長度是1。 給定 "pwwkew" ,最長子串是 "wke" ,長度是3。請注

2017年A組藍橋杯(公共問題)動態規劃

最大公共子串長度問題就是:求兩個串的所有子串中能夠匹配上的最大長度是多少。比如:"abcdkkk" 和"baabcdadabc",可以找到的最長的公共子串是"abcd",所以最大公共子串長度為4。下面的程式是採用矩陣法進行求解的,這對串的規模不大的情況還是比較有效的解法。請分

動態規劃不下降序列

求最長不下降序列求最長不下降序列求最長不下降序列 Description 設有n(n<=1000)個不相同的整數(小於32767)組成的數列,記為: a1,a2,…,an,其中任意兩個數不相同。

leetcode 矩陣中的遞增路徑 python動態規劃

題目描述 **分析:**假設最長路徑終點的是[i][j],則其最長路徑值為nums1[i][j],則nums1[i][j]等於它上下左右四個數中,比它小的數中最長路徑值最大的那一個+1 因此,我們可以從矩陣的最小值出發,其最長路徑值為1,然後計算第二小的數的最長路徑值,以此類推 cla

動態規劃——公共序列 公共

1、最長公共子序列LCS 問題,即最長公共子序列問題。它並不要求所求得的字元在所給定的字串中是連續的。比如輸入的兩個字串是 ABCBDAB 和 BDCABA,那麼,BCBA 和 BDAB 都是他們最長的公共子序列。則輸出它們的長度 4。假設兩個字串 A = [A0,A1...

動態規劃求一維陣列的大和

題目:輸入一個整形陣列,數組裡有正數也有負數。陣列中連續的一個或多個整陣列成一個子陣列,每個子陣列都有一個和。求所有子陣列的和的最大值。要求時間複雜度為O(n)。 例如,輸入的陣列為1, -2, 3,

動態規劃大正方形 (洛谷 P1387 大正方形)

代碼 log mar 最小 down 思路 計數 -m i++ 輸入格式: 輸入文件第一行為兩個整數n,m(1<=n,m<=100),接下來n行,每行m個數字,用空格隔開,0或1。 輸出格式: 一個整數,最大正方形的邊長。 輸入輸出樣例 輸入樣例: 4 4 0

算法52-----矩陣小路徑動態規劃

sum data 列表 路徑 二次 解釋 示例 一行 lse 一、題目:矩陣最小路徑 給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。 說明:每次只能向下或者向右移動一步。 示例: 輸入: [ [1,3,1],

算法56-----小編輯代價動態規劃

狀態 tro 如果 for 字符串 技術 gin 給定 clas 一、題目:最小編輯代價 給定兩個字符串str1和str2,再給定三個整數ic,dc,rc,分別代表插入、刪除、替換一個字符的代價,返回將str1編輯成str2的最小代價。舉例:str1="abc" str

演算法56-----小編輯代價動態規劃

一、題目:最小編輯代價 給定兩個字串str1和str2,再給定三個整數ic,dc,rc,分別代表插入、刪除、替換一個字元的代價,返回將str1編輯成str2的最小代價。舉例:str1="abc"   str2="adc"  ic=5    dc=3

演算法67-----環繞字串中唯一的字串動態規劃

一、題目: 把字串 s 看作是“abcdefghijklmnopqrstuvwxyz”的無限環繞字串,所以 s 看起來是這樣的:"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".  現在我們有了另一個字

動態規劃小編輯距離(字串A到字串B變化最少要多少步)

最小編輯距離是一道非常經典的動態規劃問題。 設A 和B 是2 個字串。要用最少的字元操作將字串A 轉換為字串B。  這裡所說的字元操作包括  (1)刪除一個字元;  (2)插入一個字元;  (3)將一個字元改為另一個字元。  將字串A變換為字串B 所用的最少字元操作次數也稱

動態規劃大子矩陣之和

最大子矩陣之和 題目描述 已知矩陣的大小定義為矩陣中所有元素的和。給定一個矩陣,你的任務是找到最大的非空(大小至少是11)子矩陣。 比如,如下44子矩陣 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 的最

動態規劃短路[BZOJ 1003]物流運輸trans

簡直是醉了,這道題本來想了一會兒,然後看了看資料邊的數量頂天了才400然後時間最多才100那麼直接用SPFA 複雜度O(nm2)就可以過了,然後注意一下特別判定是否超過INF可能有資料很極限,判斷一下是