最长公共子段
最长公共子段
题意
给定长度分别为 、 的两个整数序列 、,求它们的最长公共连续子段的长度。
子段必须在两个序列中都连续,但起始位置可以不同。若没有相同元素,答案为 。
例如:
a:1 2 3 2 4
b:0 2 3 2 5
最长的相同子段为 2 3 2,长度为 。
状态与转移
前面处理一个序列时,常用“以当前位置结尾”定义状态。现在有两个序列,就同时固定它们的结尾。
设 表示以 和 结尾的最长相同子段的长度。
- 若 ,可以接在以 、 结尾的相同子段后面,长度增加 。
- 若 ,不存在以这两个位置结尾的非空相同子段,长度为 。
初始化第 行、第 列为 ,表示其中一个序列为空。答案为所有状态的最大值,而不是 ,因为最长相同子段不一定在序列末尾。
不相等时必须置为 ,不能从 或 转移,否则就允许跳过元素,不再保证连续。
参考代码
输入第一行为 ,接下来两行分别为序列 、;输出最长相同子段的长度。约定 ,。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2005;
int n, m, a[N], b[N], dp[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int j = 1; j <= m; ++j) cin >> b[j];
int ans = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i] == b[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = 0;
ans = max(ans, dp[i][j]);
}
}
cout << ans << '\n';
return 0;
}
全局数组默认初始化为 。时间复杂度 ,空间复杂度 。