开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 31 天,点击查看活动详情
题目描述
给定两个长度分别为 和 的字符串 和 ,求既是 的子序列又是 的子序列的字符串长度最长是多少。
输入格式
第一行包含两个整数 和 。
第二行包含一个长度为 的字符串,表示字符串 。
第三行包含一个长度为 的字符串,表示字符串 。
字符串均由小写字母构成。
输出格式
输出一个整数,表示最大长度。
数据范围
输入样例:
4 5
acbd
abedc
输出样例:
3
题目分析
在进行DP刷题的后期过程中,发现对以往的知识出现缺漏,特来此温故。
本题为线性DP的一种,题意很简单,即求两字符串的最长公共子序列。
定义 表示字符串 中前 个位置和字符串 中前 个位置的最长公共子序列的长度。
分别对于 是否为 做出贡献分类讨论。
若 均不在 表示的最长公共子序列中,转移方程为 f[i][j] = f[i-1][j-1]。
若 在而 不在 表示的最长公共子序列中,转移方程为 f[i][j] = f[i][j-1],此时或许有一些疑问, 表示的是字符串 前 个位置和字符串 中前 个位置的最长公共子序列的长度,而当前假设肯定了 一定位于 表示的字符串中,而 一定不位于 表示的字符串中,这两种情况并不相等。但我们依旧可以如此表示,因为当前情况一定包含于 中,即保证了不漏情况,我们需要的属性为最大值,重复情况不会干扰判断。
若 不在而 在 表示的最长公共子序列中,转移方程为 f[i][j] = f[i-1][j],解释原理同上。
若 均在 表示的最长公共子序列中,转移方程为 f[i][j] = f[i-1][j-1] + 1。
最终取几种方案的最大值即可。
Accept代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N][N];
int main()
{
int n, m;
cin >> n >> m;
string a, b;
cin >> a >> b;
a = ' ' + a, b = ' ' + b;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
{
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1;
}
cout << f[n][m];
return 0;
}