最長公共子序列
一個給定序列的子序列是在該序列中刪除若干元素後得到的序列,確切的說,若給定序列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;
}