兩個字符串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;
}