最长公共子序列问题
给定两个字符串s1s2…sn和t1t2…tn。求出这两个字符串最长的公共子序列的长度.
限制条件:1<=n,m<=1000
输入:
n = 4
m = 4
s = "abcd"
t = "becd"
输出
3 ("bcd")
这个问题是被成为最长公共子序列(LCS)的著名问题。不妨用如下方式定义试试看:
定义:dp[i][j] = s[1]…s[i+1] 和 t[1]…t[j+1]对应的LCS的长度
由此,s[1]…s[i] 和 t[1]…t[j] 的公共子序列末尾追加上
(1)、s[i+1]
(2)、s[1] …s[i] 和 t[1] …t[j+1]的公共子序列
(3)、s[1] …s[i+1]和t[1]…t[j]的公共子序列
三者中的某一个,所以就有如下的递推关系成立:
(1) 当s[i+1] = t[j+1] 时,dp[i+1][j+1] = max(dp[i][j]+1,dp[i][j+1],dp[i+1][j])
(2) 当s[i+1] !=t[j+1] 时,dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j])
这个递推式可以用O(nm)的复杂度算出来,dp[n][m]就是LCS的长度。
j i | 0 | 1(b) | 2(e) | 3(c) | 4(d) |
0 | 0 | 0 | 0 | 0 | 0 |
1(a) | 0 | 0 | 0 | 0 | 0 |
2(b) | 0 | 1 | 1 | 1 | 1 |
3(d) | 0 | 1 | 1 | 2 | 2 |
4(d) | 0 | 1 | 1 | 2 | 3 |
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 1005;
int n,m;
char s[MAXN],t[MAXN];
int dp[MAXN][MAXN];
int main()
{
while(cin>>n>>m)
{
scanf("%s",s);
scanf("%s",t);
memset(dp,0,sizeof(dp));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if(s[i] == t[j])
dp[i+1][j+1] = dp[i][j] + 1;
else
dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]);
}
}
printf("%d\n",dp[n][m]);
}
return 0;
}