1. 两者区别

约定:在本文中用 LCStr 表示最长公共子串(Longest Common Substring),LCSeq 表示最长公共子序列(Longest Common Subsequence)。

子串要求在原字符串中是连续的,而子序列则没有要求。例如:

字符串 s1=abcde,s2=ade,则 LCStr=de,LCSeq=ade。

 

2. 求最长公共子串(LCStr)

算法描述:构建如下图的矩阵dp[][],当s1[i] == s2[j] 的时候,dp[i][j]=1;最后矩阵中斜对角线上最长的“1”序列的长度,就是 LCStr 的长度。

DP:LCS(最长公共子串、最长公共子序列)

但是求矩阵里斜线上的最长的“1”序列,仍然略显麻烦,我们进行如下优化:当要往矩阵中填“1”的时候,我们不直接填“1”,而是填“1”+左上角的那个数。如下图所示:

DP:LCS(最长公共子串、最长公共子序列)

这样,我们只需求出矩阵里的最大数(注意:最大数可不一定在最右下角,别误解了上图),即是 LCStr 的长度。

要求出这个 LCStr,其他的不多说了,见代码中注释。

C++ code:

 1 #include <iostream>
 2 #include <string>
 3 #include <cstdlib>         // freopen
 4 #include <cstring>         // memset
 5 using namespace std;
 6 
 7 #define MAXN 2001
 8 static int dp[MAXN][MAXN];
 9 
10 string LCStr(const string &s1, const string &s2)
11 {
12     string result;
13      
14     //s1纵向,s2横向
15     //len1行,len2列 
16     int len1=s1.length(), len2=s2.length();
17     memset(dp,0,sizeof(dp));
18     
19     //预先处理第一行第一列 
20     for(int i=0; i<len2; ++i)
21         if(s1[0]==s2[i]) dp[0][i]=1;
22     for(int i=0; i<len1; ++i)
23         if(s1[i]==s2[0]) dp[i][0]=1;
24     
25     for(int i=1; i<len1; ++i)
26     for(int j=1; j<len2; ++j)
27         if(s1[i]==s2[j]) dp[i][j]=dp[i-1][j-1]+1;    //矩阵填充 
28     
29     //将第一行的最大值移到最右边 
30     for(int i=1; i<len2; ++i)
31         if(dp[0][i]<dp[0][i-1]) dp[0][i]=dp[0][i-1];
32     
33     //从第二行开始,将每一行的最大值移到最右边
34     //最后边的数和上一行的最右边数比较大小,将大的下移
35     //到最后,右下角的数就是整个矩阵的最大值 
36     for(int i=1; i<len1; ++i)
37     {
38         for(int j=1; j<len2; ++j)
39             if(dp[i][j]<dp[i][j-1]) dp[i][j]=dp[i][j-1];
40         if(dp[i][len2-1]<dp[i-1][len2-1]) dp[i][len2-1]=dp[i-1][len2-1];
41     }
42     cout<<"length of LCStr: "<<dp[len1-1][len2-1]<<endl;
43     
44     int max = dp[len1-1][len2-1];
45     int pos_x;
46     for(int i=0; i<len1; ++i)
47     for(int j=0; j<len2; ++j)
48     {
49         if(dp[i][j]==max)
50         {
51             pos_x=i;
52             j=len2;    ///
53             i=len1;    ///快速跳出循环 
54         }
55     }
56     result=s1.substr(pos_x-max+1,max);
57     return result;
58 }
59 
60 int main()
61 {
62     int t;
63     freopen("in.txt","r",stdin);
64     cin>>t;
65     cout<<"total tests: "<<t<<endl<<endl;
66     while(t--)
67     {
68         string a,b;
69         cin>>a>>b;
70         cout<<a<<endl<<b<<endl;
71         
72         string res=LCStr(a,b);
73         cout<<"LCStr: "<<res<<endl<<endl;
74     }
75     return 0;
76 }
View Code

相关文章: