两个字符串a和b,需要统计出其中公共子序列的最长是多少。
注意:所谓子序列,指的是出现的先后顺序一样,但可以不连续出现。比如对于s=abdef,其中adf是s 的一个子序列,因为对于adf中每个字符,其出现的先后顺序与s中先后顺序一致。
这是一道DP题
状态表示
状态表示f(i,j) 表示 字符串a中(a1~ai)个字符与 字符串b中( b1 ~bj)个字符中公共子序列的最大值。
按照ai和bj是否相等来分,
如果相等,最后一位必然是相同的,
这样的话,也就是在a1~ai-1中选,和在b1 ~ bj-1中选,组成公共子序列的最大值,然后加1即可,即f(i-1,j-1)+1
如果最后一位不等,必然有一个多余
表示 |
---|
01=不包含ai,但是包含bj |
10=包含ai,但是不包含bj |
对于01,也就是在a1~ai-1中选,和在b1 ~ bj中选,组成公共子序列的最大值,f(i-1,j)
对于10,也就是在a1~ai中选,和在b1 ~ bj-1中选,组成公共子序列的最大值,即f(i,j-1)
最后f(i,j) 就与三种状态有关 :,
状态转移
f[i][j]=max(f[i-1][j],f[i][j-1]);//01和10状态必有,选择最大的
if(a[i]==b[j]) //
f[i][j]=max(f[i][j],f[i-1][j-1]+1);
最后的答案
f[n][m],n是字符串a的长度,m是字符串b的长度
acwing ac代码
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int maxn=1010;
char a[maxn],b[maxn];
int n,m;
int f[maxn][maxn];//f[i][j]表示a1-ai中和b1-bj中公共子序列的最长长度
int main(){
memset(f,0,sizeof(f));
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];//读入
for(int i=1;i<=m;i++) cin>>b[i];
for(int i=1;i<=n;i++){//遍历a
for(int j=1;j<=m;j++){//遍历b
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;
}