最长公共子序列
一个给定序列的子序列是在该序列中删除若干元素后得到的序列,确切的说,若给定序列X = {x1,x2,...xm},则另一个序列,Y= {y1,y2...,yn},当另一个序列即是X的子序列又是Y的子序列时,称Z是序列X也Y的公共子序列。最长公共子序列问题为给定序列X和Y,找到所有公共子序列中最长的一个(非连续)。
测试用例:
4 5
qwer
asdfg
4 5
qwer
qwert
4 5
qazx
qwasz
样例输出:
0
4
qwer
3
qaz
解法1(动态规划):
最长公共子序列:
使用dp[i][j] 代表字符串x的前i个字符与字符串y前j个字符之间最长公共子序列的长度
所以,i==0或者j==0时dp[i][j]=0;
1、如果x[i]==y[j]则最长公共子序列最后一个一定是x[i];
这时dp[i][j]=dp[i-1][j-1]+1
2、如果x[i]!=y[j] 此时最长公共子序列最后一个不是x[i]或者不是y[j],不确定;
所以此时取最大值max(dp[i-1][j],dp[i][j-1])。
所以此时递推方程为:
#include <stdio.h>
#include <string.h>
int dp[100][100]={0};
int a[100][100]={0};
void LCSlength(int m,int n,char x[],char y[]){
int i,j;
for(i=0;i<=m;i++)
dp[i][0]=0;
for(j=0;j<=n;j++)
dp[0][j]=0;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(x[i]==y[j]){
dp[i][j]=dp[i-1][j-1]+1;
a[i][j]=1;
}
else{
if(dp[i-1][j]>dp[i][j-1]){
dp[i][j]=dp[i-1][j];
a[i][j]=2;
}
else{
dp[i][j]=dp[i][j-1];
a[i][j]=3;
}
}
}
}
}
void LCS(int i,int j,char x[])
{
if(i==0 || j==0)
return;
else if(a[i][j]==1){
LCS(i-1,j-1,x);
printf("%c",x[i]);
}else if(a[i][j]==2){
LCS(i-1,j,x);
}else{
LCS(i,j-1,x);
}
}
int main()
{
char x[100];
char y[100];
int m,n;
scanf("%d%d",&m,&n);
getchar();
for(int i=1;i<=m;i++)
scanf("%c",&x[i]);
getchar();
for(int i=1;i<=n;i++)
scanf("%c",&y[i]);
LCSlength(m,n,x,y);
LCS(m,n,x);
printf("\n%d\n",dp[m][n]);
return 0;
}
解法二(递归):
#include <stdio.h>
#include <string.h>
int c[100][100];
int LCSlength(char *a,char *b,int t,int r)
{
if(t==0 || r==0)
return 0;
if(a[t-1]==b[r-1]){
c[t][r]=LCSlength(a,b,t-1,r-1)+1;
}else {
int x=LCSlength(a,b,t-1,r);
int y=LCSlength(a,b,t,r-1);
c[t][r]=x>y?x:y;
}
return c[t][r];
}
int main()
{
char str1[100],str2[100];
while(~scanf("%s %s",str1,str2))
{
memset(c,0,sizeof(c));
printf("%d\n",LCSlength(str1,str2,strlen(str1),strlen(str2)));
}
return 0;
}
解法三(备忘录):
#include <stdio.h>
#include <string.h>
int c[100][100];
int LCSlength(char *a,char *b,int t,int r)
{
if(c[t][r]>0)
return c[t][r];
else if(t==0 || r==0)
return 0;
if(a[t-1]==b[r-1]){
c[t][r]=LCSlength(a,b,t-1,r-1)+1;
}else {
int x=LCSlength(a,b,t-1,r);
int y=LCSlength(a,b,t,r-1);
c[t][r]=x>y?x:y;
}
return c[t][r];
}
int main()
{
char str1[100],str2[100];
while(~scanf("%s %s",str1,str2))
{
memset(c,0,sizeof(c));
printf("%d\n",LCSlength(str1,str2,strlen(str1),strlen(str2)));
}
return 0;
}