最长公共子序列(31-36)

96 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 31 天,点击查看活动详情

题目描述

给定两个长度分别为 NN 和 MM 的字符串 AA 和 BB,求既是 AA 的子序列又是 BB 的子序列的字符串长度最长是多少。

输入格式

第一行包含两个整数 NN 和 MM

第二行包含一个长度为 NN 的字符串,表示字符串 AA

第三行包含一个长度为 MM 的字符串,表示字符串 BB

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

输出格式

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

数据范围

1N,M10001≤N,M≤1000

输入样例:

4 5
acbd
abedc

输出样例:

3

题目分析

在进行DP刷题的后期过程中,发现对以往的知识出现缺漏,特来此温故。

本题为线性DP的一种,题意很简单,即求两字符串的最长公共子序列。

定义 f[i][j]f[i][j] 表示字符串 aa 中前 ii 个位置和字符串 bb 中前 jj 个位置的最长公共子序列的长度。

分别对于 a[i],  b[j]a[i],\; b[j]是否为 f[i][j]f[i][j] 做出贡献分类讨论。

a[i],  b[j]a[i],\; b[j] 均不在 f[i][j]f[i][j] 表示的最长公共子序列中,转移方程为 f[i][j] = f[i-1][j-1]

a[i]a[i] 在而 b[j]b[j] 不在 f[i][j]f[i][j] 表示的最长公共子序列中,转移方程为 f[i][j] = f[i][j-1],此时或许有一些疑问,f[i][j1]f[i][j-1] 表示的是字符串 aaii 个位置和字符串 bb 中前 jj 个位置的最长公共子序列的长度,而当前假设肯定了 a[i]a[i] 一定位于 f[i][j1]f[i][j-1] 表示的字符串中,而 b[j]b[j] 一定不位于 f[i][j1]f[i][j-1] 表示的字符串中,这两种情况并不相等。但我们依旧可以如此表示,因为当前情况一定包含于 f[i][j1]f[i][j-1] 中,即保证了不漏情况,我们需要的属性为最大值,重复情况不会干扰判断。

a[i]a[i] 不在而 b[j]b[j]f[i][j]f[i][j] 表示的最长公共子序列中,转移方程为 f[i][j] = f[i-1][j],解释原理同上。

a[i],  b[j]a[i],\; b[j] 均在 f[i][j]f[i][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;
}