最長公共子序列

最長公共子序列

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



發佈了161 篇原創文章 · 獲贊 70 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章