11077 最长公共子字符串(优先做)
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA
Description
求两个输入序列的最长的公共子字符串的长度。子字符串中的所有字符在源字符串中必须相邻。
如字符串:21232523311324和字符串312123223445,他们的最长公共子字符串为21232,长度为5。
输入格式
两行,第一行为第一个字符串X,第二行为第二个字符串Y,字符串不含空格并以回车标示结束。X和Y的串长都
不超过10000。
输出格式
两行,第一行为最长的公共子字符串的长度,第二行输出一个最长的公共子字符串。
说明:
(1)若最长的公共子字符串有多个,请输出在源字符串X中靠左的那个。
(2)若最长公共子字符串的长度为0,请输出空串(一个换行符)。
如输入:
21232523311324
152341231
由于523和123都是最长的公共子字符串,但123在源串X中更靠左,因此输出:
3
123
解题思路
此题思路类似:算法设计与分析 SCAU11084 多个串的最长公共子序列
动态规划
以下解释中
- text1[0, i] 代表字符串 text1 的前 i + 1 个字符
- text2[0, j] 代表字符串 text2 的前 j + 1 个字符
状态定义:dp[i][j] 的值代表 text1 字符串前 i 个字符和 text2 字符串前 j 个字符的最长公共子字符串的长度。
假设字符串 text1 和 text2 的长度分别为 m 和 n,创建 m+1 行 n+1 列的二维数组 dp,其中 dp[i][j] 表示 text1[0, i] 和 text2[0, j] 的最长公共子字符串的长度。
例如:dp[3][4] 代表 text1 字符串前三个字符和 text2 字符串前四个字符的最长公共子字符串的长度。
注意
-
这题求的是最长公共子串,不是最长公共子序列,子序列可以是不连续的,但子串一定是连续的。
-
定义 dp[i][j] 表示字符串 str1 中第 i 个字符和 str2 种第 j 个字符为最后一个元素所构成的最长公共子串。如果要求 dp[i][j],也就是 str1 的第 i 个字符和 str2 的第 j 个字符为最后一个元素所构成的最长公共子串,我们首先需要判断这两个字符是否相等。
-
如果不相等,那么他们就不能构成公共子串,也就是
dp[i][j] = 0; -
如果相等,我们还需要计算前面相等字符的个数,其实就是 dp[i - 1][j - 1],所以 dp[i][j] = dp[i - 1][j - 1] + 1;
复杂度分析:
-
时间复杂度:O(mn),其中 m 和 n 分别是字符串 text1 和 text2 的长度。二维数组 dp 有 m + 1 行和 n + 1 列,需要对 dp 中的每个元素进行计算。
-
空间复杂度:O(mn),其中 m 和 n 分别是字符串 text 1和 text 2的长度。创建了 m + 1 行 n + 1 列的二维数组 dp。
更多注释可查看代码中,有助于理解
代码如下
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cstring>
#include <string>
using namespace std;
int maxLength = 0;
int maxEndIndex = 0;
void maxCommonLength(string a, string b) {
int m = a.length(), n = b.length();
int dp[m + 1][n + 1];
for(int i = 0; i <= m; i++) {
for(int j = 0; j <= n; j++) {
// 长度为0,公共肯定是0
if(i == 0 || j == 0) {
dp[i][j] = 0;
} else {
// 如果i索引的m串 和 j索引的n串字符相同,那就+1,同一行的前一个,因为是一行一行遍历的
if(a[i - 1] == b[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if(dp[i][j] > maxLength) {
maxLength = dp[i][j];
maxEndIndex = i - 1;
}
} else {
// 由于得连续,所以直接置为0,而不是拿上次的状态
dp[i][j] = 0;
}
//printf("i=%d j=%d,dp=%d\n", i, j, dp[i][j]);
}
}
}
}
int main()
{
string s1, s2;
cin >> s1 >> s2;
maxCommonLength(s1, s2);
cout << maxLength << endl;
cout << s1.substr(maxEndIndex - maxLength + 1, maxLength) << endl;
return 0;
}