子序列是指从给定的序列中随意地(不一定是连续的)去掉若干元素后所形成的的序列
最长公共子序列,是指多个字符串中具有的长度最大的公共的子序列。
求两个序列的最长公共子序列:
设两个序列为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;
}