题目描述
给定两个长度为 n n n 个字符串 s 1 s1 s1、 s 2 s2 s2,要求找出其中公共的序列部分。
数据规模
1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000
样例输入
a b c d
b c e d
样例输出
3
问题求解
运用 dp 来做,定义一个 dp
数组。
dp[i][j]
:
S
1
S1
S1 前 i 个字符串和
S
2
S2
S2 的前 j 个字符串所含有的最长公共子序列。有如下方程:
d
p
[
i
]
[
j
]
=
{
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
,
s1[i] != s2[j]
d
p
[
i
−
1
]
[
j
−
1
]
+
1
,
s1[i] = s2[j]
dp[i][j] = \begin{cases} max(dp[i - 1][j], dp[i][j - 1]), & \text{s1[i] != s2[j] } \\ dp[i - 1][j - 1] + 1, & \text{s1[i] = s2[j]} \end{cases}
dp[i][j]={max(dp[i−1][j],dp[i][j−1]),dp[i−1][j−1]+1,s1[i] != s2[j] s1[i] = s2[j]。
规划的表格如下:
i/ j | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 1 | 1 |
2 | 0 | 0 | 1 | 2 | 2 |
3 | 0 | 0 | 1 | 2 | 2 |
4 | 0 | 0 | 1 | 2 | 3 |
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5e3;
int dp[N][N];
char s1[N];
char s2[N];
int n;
int m;
void solve() {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (s1[i] == s2[j]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else {
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
}
}
cout << dp[n][m] << endl;
}
int main(int argc, char** argv) {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> s1[i];
}
for (int i = 1; i <= m; ++i) {
cin >> s2[i];
}
solve();
return 0;
}