乙個字串s,去掉零個或者多個元素所剩下的子串稱為s的子串行。最長公共子串行就是尋找兩個給定序列的子串行,該子串行在兩個序列中以相同的順序出現,但是不必要是連續的。
例如序列x=abcbdab,y=bdcaba。序列bca是x和y的乙個公共子串行,但是不是x和y的最長公共子串行,子串行bcba是x和y的乙個lcs,序列bdab也是。
尋找lcs的一種方法是列舉x所有的子串行,然後注意檢查是否是y的子串行,並隨時記錄發現的最長子序列。假設x有m個元素,則x有2^m個子序列,指數級的時間,對長序列不實際。
使用動態規劃求解這個問題,先尋找最優子結構。設x=和y=為兩個序列,lcs(x,y)表示x和y的乙個最長公共子串行,可以看出
如果xm=yn,則lcs ( x,y ) = xm + lcs ( xm-1,yn-1 )。
如果xm!=yn,則lcs( x,y )= max
lcs問題也具有重疊子問題性質:為找出x和y的乙個lcs,可能需要找x和yn-1的乙個lcs以及xm-1和y的乙個lcs。但這兩個子問題都包含著找xm-1和yn-1的乙個lcs,等等.
dp最終處理的還是數值(極值做最優解),找到了最優值,就找到了最優方案;為了找到最長的lcs,我們定義dp[i][j]記錄序列lcs的長度,合法狀態的初始值為當序列x的長度為0或y的長度為0,公共子串行lcs長度為0,即dp[i][j]=0,所以用i和j分別表示序列x的長度和序列y的長度,狀態轉移方程為
dp[i][j] = 0 如果i=0或j=0
dp[i][j] = dp[i-1][j-1] + 1 如果x[i-1] = y[i-1]
dp[i][j] = max 如果x[i-1] != y[i-1]
求出了最長公共子串行的長度後,輸出lcs就是輸出dp的最優方案了,既可以用乙個額外的矩陣儲存路徑,也可以直接根據狀態轉移矩陣倒推最優方案。
#include #include #define maxlen 100
void lcslength(char *x, char *y, int m, int n, int c[maxlen], int b[maxlen])
else if(c[i-1][j] >= c[i][j-1])else}}
}void printlcs(int b[maxlen], char *x, int i, int j)
else if(b[i][j] == 1)
printlcs(b, x, i-1, j);
else
printlcs(b, x, i, j-1);
}int main(int argc, char **argv)
; char y[maxlen] = ;
int b[maxlen][maxlen];
int c[maxlen][maxlen];
int m, n;
m = strlen(x);
n = strlen(y);
lcslength(x, y, m, n, c, b);
printlcs(b, x, m, n);
return 0;
}
如果不需要輸出序列,則可以使用滾動陣列的方式
#include using namespace std;
//滾動陣列
int dp[2][21]; //儲存lcs長度
char x[21];
char y[21];
int i, j, k;
void main()
else if(dp[k][j-1] > dp[k^1][j])
else}}
printf("len of lcs is: %d\n", dp[k][ylen]);
}
最長公共子串行 最長公共子串
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...
最長公共子串行 最長公共子串
1.區別 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。2 最長公共子串 其實這是乙個序貫決策問題,可以用動態規劃來求解。我們採用乙個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧 bab 和 caba 當然我們現在一眼就可以看出來最長公...
最長公共子串 最長公共子串行
子串要求連續 子串行不要求連續 之前的做法是dp求子序列 include include include using namespace std const int inf 0x3f3f3f3f const int mod 1000000007 string s1,s2 int dp 1010 10...