最长公共子串(LCS)
2019-05-16 / Luo Jinrong   

问题

最长公共子串(Longest Common Substring)问题,对与给定的两个字符串,求它们的最长公共子串,注意:子串是连续的。


暴力方法

遍历每一个子串,进行比较,一个长度为$n$的字符串拥有$n^2$个子串,所以该方法的复杂度为$O(n^4)$。


动态规划

把问题分解的若干个子问题求解,开一个$n×n$的数组存以当前位置结尾的最长公共子串,dp[i][j]表示字符串1的第i位与字符串2的第j位结尾的最长子串。

  • 状态转移方程如下:

$$
dp[i][j]=\begin{cases}
0,str1[i]!=str2[j]\\
dp[i-1][j-1]+1,str1[i]=str2[j]
\end{cases}
$$

  • 代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Longest Common Substring
#include<bits/stdc++.h>
using namespace std;
string s1, s2;
const int maxn = 1e4 + 5;
int dp[maxn][maxn], maxlen;
int main() {
while (cin >> s1 >> s2) {
int len1 = s1.length(), len2 = s2.length();
maxlen = 0;
for (int i = 0; i <= len1; i++) {
dp[i][0] = 0;
}
for (int i = 0; i <= len2; i++) {
dp[0][i] = 0;
}
for (int i = 0; i < len1; i++) {
for (int j = 0; j < len2; j++) {
if (s1[i] == s2[j]) {
dp[i + 1][j + 1] = dp[i][j] + 1;
}
else {
if (dp[i][j] > maxlen) {
maxlen = dp[i][j];
}
dp[i + 1][j + 1] = 0;
}
}
if (dp[i][len2] > maxlen) {
maxlen = dp[i][len2];
}
}
if (dp[len1][len2] > maxlen) {
maxlen = dp[len1][len2];
}
cout << maxlen << "\n";
}
}

问题扩展(最长公共子序列)

  • 公共子序列问题比子串问题要简单一些,因为最后最大值就存在dp数组的最后一个位置,不需要通过其他方法获取
  • 状态转移方程如下:

$$
dp[i][j]=\begin{cases}
max(dp[i-1][j],dp[i][j-1]),str1[i]!=str2[j]\\
dp[i-1][j-1]+1,str1[i]=str2[j]
\end{cases}
$$

  • 代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Longest Common Substring
#include<bits/stdc++.h>
using namespace std;
string s1, s2;
const int maxn = 1e4 + 5;
int dp[maxn][maxn], maxlen;
int main() {
while (cin >> s1 >> s2) {
int len1 = s1.length(), len2 = s2.length();
maxlen = 0;
for (int i = 0; i <= len1; i++) {
dp[i][0] = 0;
}
for (int i = 0; i <= len2; i++) {
dp[0][i] = 0;
}
for (int i = 0; i < len1; i++) {
for (int j = 0; j < len2; j++) {
if (s1[i] == s2[j]) {
dp[i + 1][j + 1] = dp[i][j] + 1;
}
else {
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
}
}
}
cout << dp[len1][len2] << "\n";
}
}

return 0;


本文链接:
https://luojinrong.github.io/2019/05/16/最长公共子串-LCS/