最長公共子串——動態規劃求解

上篇總結了最長公共子序列用動態規劃求解的問題,由此也引出了最長公共子串使用動態規劃思想求解的問題。ios

再次辨析下二者的關係,算法

最長公共子序列 VS 最長公共子串:數組

找兩個字符串的最長公共子串,這個子串要求在原字符串中是連續的。而最長公共子序列則並不要求連續。spa

其實話句話說最長公共子序列中包含着最長公共子串code

其實最長公共子串的算法求解思想與最長公共子序列的思路基本相似。blog

 

1.在最長公共子序列中,核心的遞推式以下:ci

若xi=yj=zk,c[i][j] = c[i-1][j-1] + 1;字符串

若xi≠yj,xi≠zk,c[i][j] = c[i-1][j] ;string

若xi≠yj,yj≠zk,c[i][j] = c[i][j-1] ;io

 

2.可是在最長公共子串中,要求原字符串是連續的,那麼就須要對最長公共子序列的核心遞推式進行修改了。

在最長公共子串中,咱們一樣創建c[i][j]來保存兩個序列的字符異同狀況,因爲最長公共子串要求串必須是連續的,因此,在xi≠yj時,咱們就須要將c[i][j]記爲0,若相同則記爲1。

根據下圖,在對角線上連續爲1的表示兩個字符串是相同的,並且,對角線上連續的1越多,表示兩個字符串的最長公共子串越長,咱們可以發現,下圖的最長爲三個1,因此其長度爲3,最長公共子串爲DCD。

 

 

3.上述咱們還須要針對對角線上連續1的個數進行彙總,這樣才能求得最長公共子串的長度。

咱們能夠針對上面的遞推式進行修改,咱們知道,要是xi和yj是屬於一個公共子串的最後一個字符(假設其長度大於等於2),那麼必定有xi==yj&&xi-1 = =yj-1。

因此,咱們在求c[i][j]時,要是X[i]==Y[j],c[i][j] = c[i-1][j-1] + 1,不管 xi==yj是否相等。

那麼咱們就能夠對上圖進行更新了,更新以下:

上圖咱們只要遍歷數組就能獲得最長公共子串的長度。

 

4.上述的思惟,咱們能夠求出兩個字符串的最長公共子串的長度,可是,咱們還須要輸出最長的公共子串中的元素是是什麼,這就要求咱們用一個額外的空間進行記錄。

由於最長公共子串確定爲兩個字符串的子集,因此其長度必然小於等於兩個字符串的長度。

咱們能夠藉助兩個變量對最大長度以及最大長度的中止下標進行記錄,分別藉助maxLen,flag;

在循環中以此將數組中最大的數賦值給maxLen,並用flag來記錄此時的行/列字符串的下標,後續能夠進行遍歷。

上述已經將整個思路理清,那麼下面放代碼:

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 const int N=1024;
 5 int c[N][N];
 6 int maxLen=0,flag=0;
 7 char s1[N],s2[N];
 8 int len1,len2;
 9 void LCSs()
10 {
11     for(int i = 1; i <= len1; i++){
12         for(int j = 1; j <= len2; j++){
13             if(s1[i-1] == s2[j-1]){ //注:此處的s1與s2序列是從s1[0]與s2[0]開始的
14                 c[i][j] = c[i-1][j-1] + 1;
15                 if(c[i][j] > maxLen){
16                     maxLen = c[i][j];
17                     flag = j;   //注:此處的flag在s2中尋找應該從s2[flag-maxLen]-s2[flag-1]尋找
18                 }
19             }
20             else{
21                 c[i][j] = 0;
22             }
23 
24         }
25     }
26 }
27 
28 void LCSs_PRINT(int flag,int maxLen,int len2 )
29 {
30     if(flag==0 || maxLen==0){
31         return;
32     }
33     for(int i = flag-maxLen; i < flag; i++){
34         cout << s2[i];
35     }
36 }
37 
38 int main()
39 {
40     cout << "請輸入X字符串" << endl;
41     cin >> s1;
42     cout << "請輸入Y字符串" << endl;
43     cin >> s2;
44     len1 = strlen(s1);
45     len2 = strlen(s2);
46     for(int i = 0; i <= len1; i++){
47         c[i][0] = 0;
48     }
49     for(int j = 0; j <= len2; j++){
50         c[0][j] = 0;
51     }
52     LCSs();
53     cout << "s1與s2的最長公共子序列的長度是:" << maxLen <<endl;
54     cout << "s1與s2的最長公共子序列是:";
55     LCSs_PRINT(flag,maxLen,len2);
56     return 0;
57 }
相關文章
相關標籤/搜索