AcWing 897. 最长公共子序列

\(AcWing\) \(897\). 最长公共子序列

一、题目描述

给定两个长度分别为 \(N\)\(M\) 的字符串 \(A\)\(B\),求既是 \(A\) 的子序列又是 \(B\)的子序列的字符串 长度最长 是多少。

输入格式
第一行包含两个整数 \(N\)\(M\)

第二行包含一个长度为 \(N\) 的字符串,表示字符串 \(A\)

第三行包含一个长度为 \(M\) 的字符串,表示字符串 \(B\)

字符串均由小写字母构成。

输出格式
输出一个整数,表示最大长度。

数据范围
\(1≤N,M≤1000\)

输入样例

4 5
acbd
abedc

输出样例

3

二、\(LCS\)问题分析

状态表示
定义\(f[i][j]\)\(a[]\)\(i\)结尾,\(b[]\)\(j\)结尾的最长公共子序列长度

说明:没有说\(a[i]\)或者\(b[j]\)一定要出现在最长公共子序列当中!这个最长公共子序列,可能是\(a[]\)\(b[]\)的一些前序组成的,\(a[i],b[j]\)也可能没有对结果产生贡献。

  • \(a[i]==b[j]\)时,看一下两个字符串的前序,发现在少了\(a[i],b[j]\)后,转化为子问题\(f[i-1][j-1]\),问题转化为$$f[i][j]=f[i-1][j-1]+1$$

  • \(a[i] \neq b[j]\)时:

    • 如果\(a[i]\)不产生贡献,那么把它干掉\(f[i-1][j]\)
    • 如果\(b[j]\)不产生贡献,那么把它干掉\(f[i][j-1]\)
    • 如果两个都没有贡献,那么就是\(f[i-1][j-1]\)

三、实现代码

#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
int n, m;
char a[N], b[N];
int f[N][N];

int main() {
    // 递推式出现f[i-1][j-1],如果i,j从0开始会出现负值,所以下标从1开始
    cin >> n >> m >> a + 1 >> b + 1;
    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;
        }
    printf("%d", f[n][m]);
    return 0;
}

posted @ 2021-10-20 16:10  糖豆爸爸  阅读(284)  评论(0编辑  收藏  举报
Live2D