最长公共子序列Lcs
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:
abcicba
abdkscab
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
Input
第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)
Output
输出最长的子序列,如果有多个,随意输出1个。
Sample Input
abcicba abdkscab
Time limit
1000 ms
Memory limit
131072 kB
Author
李陶冶
Sample Output
abca
题解:经典的DP问题。
状态dp[i][j]:a串的前i项和b串的前j项以b[j]项为结尾构成的LCIS的长度.
状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(a[i]==b[j]?1:0))。
ps:如果a串的i项和b串的j项相等,dp[i][j]就等于dp[i][j]+1,否则就等于前一个其他情况中的最大值。
这一题的难点在于如何回溯找到路线。博主也蒙呀,看了好多博客,找到了一个很好理解很简介的思路方法:当dp[i][j]最大的时候,就是a[i][j]==b[i][j]的时候。不断找到dp[i][j]的最大值,直到i或者j等于0,也就回溯了找到最长公共子序列的路线。
具体代码如下:
#include<iostream>
using namespace std;
int dp[1002][1002]={0};
int MAX(int a,int b,int c)
{
if(c>b)
b=c;
return a>b?a:b;
}
int main()
{
char final[1002]={0};
char a[1002],b[1002];
scanf("%s%s",a+1,b+1);
int i,j;
for(i=1;a[i];i++)
for(j=1;b[j];j++)
dp[i][j]=MAX(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(a[i]==b[j]?1:0));
i--;
j--;
int k=1001;
while(i>0&&j>0)
if(a[i]==b[j])
{
final[k--]=a[i];
i--;
j--;
}else if(dp[i-1][j]>dp[i][j-1])
i--;
else j--;
printf("%s\n",final+k+1);
return 0;
}
ps:有什么问题或者错误,大佬们在评论留言呀,我会改的,谢谢!