题目
题目描述
给定两个字符串,寻找这两个字串之间的最长公共子序列。
输入
输入两行,分别包含一个字符串,仅含有小写字母。
输出
最长公共子序列的长度。
样例输入
abcdgh
aedfhb
样例输出
3
解题思路
本题是典型的动态规划求最长公共子序列(LCS)的题目。首先,为了更直观地帮助理解动态转移方程,根据题目所给样例绘制如下表格:
表格中dp[i][j]位置的数值含义是,当取1-i个第一个字符串(令其为a)的字母和取1-j个第二个字符串的字母(令其为b),最长公共子序列的长度是dp[i][j]。具体填表的过程可以以如下状态转移方程来表示:
d p [ i ] [ j ] = { 0 ( i = 0 或 j = 0 ) d p [ i − 1 ] [ j − 1 ] + 1 ( i ! = 0 且 j ! = 0 且 a [ i ] = = b [ j ] ) m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) ( i ! = 0 且 j ! = 0 且 a [ i ] ! = b [ j ] ) dp[i][j]=\left\{ \begin{aligned} &0 &(i=0 或 j=0)\\ dp[i-1]&[j-1]+1 &(i!=0 且 j!=0 且 a[i]==b[j])\\ max(dp[i-1]&[j],dp[i][j-1])&(i!=0 且 j!=0 且 a[i]!=b[j])\\ \end{aligned} \right. dp[i][j]=⎩ ⎨ ⎧dp[i−1]max(dp[i−1]0[j−1]+1[j],dp[i][j−1])(i=0或j=0)(i!=0且j!=0且a[i]==b[j])(i!=0且j!=0且a[i]!=b[j])
由此,可以时间复杂度为O(n2)来获得dp动态规划数组,而dp[lena][lenb]即为所求的子序列的最大长度。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a,b;
int i,j,lena,lenb;
cin >> a >> b;
lena = a.size();
lenb = b.size();//长度
int dp[lena+1][lenb+1];//动态规划
for (i=0;i<=lenb;i++)//初始化
dp[0][i] = 0;//当a不取任何字母,最长公共子序列长度一定为0
for (i=0;i<=lena;i++)
dp[i][0] = 0;//当b不取任何字母,最长公共子序列长度一定为0
for (i=1;i<=lena;i++)
{
for (j=1;j<=lenb;j++)
{
if (a[i-1]==b[j-1])
dp[i][j] = dp[i-1][j-1]+1;
else
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
printf("%d",dp[lena][lenb]);
return 0;
}