最长公共子序列

197 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

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

输入格式

第一行包含两个整数 N 和 M。

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

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

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

输出格式

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

数据范围

1≤N,M≤1000

输入样例:

4 5
acbd
abedc

输出样例:

3

思路

我们通过题目可以很容易发现这是一道动态规划的问题,那动态规划的问题我们总结过可以使用状态表示f[i,j]和状态计算两个角度进行思考。

状态表示f[i, j]

  • 集合:数组f[i, j]代表了一个集合,这个集合表示所有在第一个序列的前i个字母中出现,且在第二个序列的前j个子母中出现的子序列
  • 属性:集合每个属性代表的含义是当前状态的最大值

状态计算

可以把f[i, j]划分为多个状态

1、不取a[i]并且不取b[i],对应的集合表达式:f[i -1, j - 1]

2、取a[i]并且不取b[i],对应的集合表达式:f[i -1, j ]

3、不取a[i]并且取b[i],对应的集合表达式:f[i, j - 1]

4、取a[i]并且取b[i],对应的集合表达式:f[i -1, j - 1] + 1

代码

#include <iostream>
​
using namespace std;
​
const int N = 1010; 
​
​
char a[N],b[N];
int f[N][N];
int n ,m;
​
int main()
{
    cin >> n >> m;
    scanf("%s",a + 1);
    scanf("%s",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] = max(f[i][j], f[i - 1][j - 1] + 1);
        }
    }
    cout << f[n][m] << endl;
    return 0;
}
​

\