先来看一下基本概念
1、公共子序列:给定两个序列X和Y,如果Z既是X的子序列,又是Y的子序列,那么称Z是X和Y的公共子序列。
2、最长公共子序列:求公共子序列中长度最长的。
最长公共子序列问题,简称LCS问题,下边说一下求解思路:
步骤一:刻画最长公共子序列的特征:
前缀:给定一个序列X={x1,x2,x3...xm},对于i=1...m,定义X的第i前缀Xi={x1,x2,..xi};
结论:两序列的LCS包含两序列的前缀的LCS。因此,LCS问题具有最优子结构性质。
步骤二:
定义c[i,j]表示X和Y的LCS长度,下边给出递归式:
步骤三:
自底向上的动态规划方法:
void LCS_down2up(DataType X[],int m,DataType Y[],int n,int c[M+1][N+1],char b[M+1][N+1])
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(X[i-1]==Y[j-1])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]='D'; //D means diagonal(对角线)
}
else
{
c[i][j]=max(c[i-1][j],c[i][j-1]);
if(c[i-1][j]>c[i][j-1])
b[i][j]='T'; // T means top
else b[i][j]='L'; // L means left
}
}
}
}
c数组保存最大子序列长度,b数组记录子问题的调用方向
步骤四、构造LCS
void print_result(char b[M+1][N+1],DataType X[],int i,int j)
{
if(i==0 || j==0) ;
else {
if(b[i][j]=='D')
{
print_result(b,X,i-1,j-1);
cout<<X[i-1];
}
else if(b[i][j]=='T')
print_result(b,X,i-1,j);
else print_result(b,X,i,j-1);
}
}
其实最大公共子序列并非只有一个,我们所做的只是找出了满足条件的一个最优解而已,所以在运行测试代码时,我们构造解的起点不同,最后打印的LCS也不同。
测试代码
#include <iostream>
#define M 7
#define N 6
typedef char DataType;
using namespace std;
//down to top
void LCS_down2up(DataType X[],int m,DataType Y[],int n,int c[M+1][N+1],char b[M+1][N+1])
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(X[i-1]==Y[j-1])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]='D'; //D means diagonal(对角线)
}
else
{
c[i][j]=max(c[i-1][j],c[i][j-1]);
if(c[i-1][j]>c[i][j-1])
b[i][j]='T'; // T means top
else b[i][j]='L'; // L means left
}
}
}
}
void print_result(char b[M+1][N+1],DataType X[],int i,int j)
{
if(i==0 || j==0) ;
else {
if(b[i][j]=='D')
{
print_result(b,X,i-1,j-1);
cout<<X[i-1];
}
else if(b[i][j]=='T')
print_result(b,X,i-1,j);
else print_result(b,X,i,j-1);
}
}
int main()
{
DataType X[]={'a','b','c','b','d','a','b'},Y[]={'b','d','c','a','b','a'};
int c[M+1][N+1]={0};
char b[M+1][N+1]={0};
LCS_down2up(X,M,Y,N,c,b);
cout<<"the list of result : "<<endl;
for(int i=1;i<M+1;i++)
{
for(int j=1;j<N+1;j++)
{
cout<<c[i][j]<<"\t";
}
cout<<endl;
}
cout<<"b list:"<<endl;
for(int i=1;i<M+1;i++)
{
for(int j=1;j<N+1;j++)
{
cout<<b[i][j]<<"\t";
}
cout<<endl;
}
print_result(b,X,6,6);
cout<<endl;
print_result(b,X,7,6);
return 0;
}