最长公共子序列

子序列是指从给定的序列中随意地(不一定是连续的)去掉若干元素后所形成的的序列

最长公共子序列,是指多个字符串中具有的长度最大的公共的子序列。

求两个序列的最长公共子序列:

设两个序列为X(i)=x1x2x3.........xi    其中i为序列X的长度  Y(j)=y1y2y3.........yj    其中j 为序列Y 的长度。设序列X(i) 和序列Y(j) 的最长公共子序列为

Z(k)=z1z2z3.........zk  

用动态规划的方法:

步骤1描述最优解的结构:      

情况1 :如果xi=yj,则有zk=xi=yj    Z(k-1) 为序列X(i-1)和序列Y(j-1) 最长公共子序列

情况2 : 如果xi!=yj 则有zk!=xi   蕴含着Z(k) 为序列X(i-1)和序列Y(j) 的最长公共子序列

情况3: 如果xi!=yj   则有zk!=yj  蕴含着Z(k) 为序列X(i) 和序列Y(j-1) 的最长公共子序列


步骤2递归的定义最优解的值

设LCS(i,j) 表示序列X(i) 和序列Y(j) 的最长公共子序列的长度 则


步骤3计算最优解的值: 自底而上的求出最优解的值。         在求解过程中维持一个二维数组message[i][j]   用于记录使得   LCS[i][j] 取得最优值的最优子结构


步骤4 ;构造最优解的值:求最长公共子序列的长度是比较容易,在求最长公共子序列为啥时要用到messae 里的信息  沿着箭头方向回溯找到最长公共秩序列



#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int ** LongestLength(char *str1,char*str2,int*commonLength)//最长公共子序列的长度通过 commonLength 返回
{
	int length1=strlen(str1);
	int length2=strlen(str2);
    int ** LCS=new int*[length1+1];//注意此处有个加一
	int **message =new int*[length1+1];//注意此处有个加一  其中message 用于记录使得l[i,j] 取最优值的最优子结构
	for(int i=0;i<=length1;i++)//此处都是小于等于
	{
	     LCS[i]=new int[length2+1];
		 message[i]=new int[length2+1];
	}
	for(int i=0;i<=length1;i++)//此处都是小于等于     
	{
	    LCS[i][0]=0;
	}
	for(int j=0;j<=length2;j++)//此处都是小于等于
	{
	    LCS[0][j]=0;
	}
	for(int i=1;i<=length1;i++)
	{
	    for(int j=1;j<=length2;j++)
		{
		      if(str1[i-1]==str2[j-1])
			  {
			       LCS[i][j]=LCS[i-1][j-1]+1;
				   message[i][j]=0;//0 代表向右上方的箭头
			  }
			  else if(LCS[i-1][j]>=LCS[i][j-1])
			  {
			       LCS[i][j]=LCS[i-1][j];
				   message[i][j]=1;//1代表向上方的箭头
			  }
			  else
			  {
			      LCS[i][j]=LCS[i][j-1];
				   message[i][j]=2;//2代表向左边的箭头
			  }
		}
	}
	*commonLength=LCS[length1][length2];
	//释放l 的内存
	for(int i=0;i<length1;i++)
	{
	    delete LCS[i];
	}
	delete LCS;
	return message;
}
void OutputLCS(char *str1,char* str2,int length1,int length2,int**message)//逆序回溯输出最长公共子序列时用递归
{
   
	 if(length1==0||length2==0)
	 {
	    return;
	 }
	 if(message[length1][length2]==0)//结合前面LongestLength 看   0 代表向右上方的箭头
	 {
	      OutputLCS(str1,str2,length1-1,length2-1,message);//递归的形式
		  printf("%c",str1[length1-1]);
	 }
	 else if(message[length1][length2]==1)结合前面LongestLength 看   1 代表向上方的箭头
	 {
		 OutputLCS(str1,str2,length1-1,length2,message);
	 }
	 else if(message[length1][length2]==2)结合前面LongestLength 看   2代表向左边的箭头
	 {
	      OutputLCS(str1,str2,length1,length2-1,message);
	 }
}
int main()
{
	    //char str1[1000]="ABCBDAB",str2[1000]="BCDB";
		char str1[1000],str2[1000];
		int n;
		int **message;
		while(1)
		{
			cout<<"please input str1"<<endl;
		    int commonLength;
			cin>>str1;
			cout<<"please input str2"<<endl;
			cin>>str2;
			message=LongestLength(str1,str2,&commonLength);
			cout<<commonLength<<endl;
			cout<<"the common substr is: "<<endl;
			OutputLCS(str1,str2,strlen(str1),strlen(str2),message);
			cout<<endl;
		}
	
    return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值