最长公共子序列

来源:互联网 发布:同花顺云计算 编辑:程序博客网 时间:2024/06/06 07:36

子序列:一个给定的子序列时在该序列中删除若干元素后得到的序列。

最长公共子序列定义:给定两个序列X和Y,当另一个序列Z及时X的子序列又是Y的子序列时,称Z是X和Y的子序列。


本文用例:X = {A,B,C,B,D,A,B},Y = {B,D,C,A,B,A};Z= {B,C,A,B};

在两个算法有多个最长公共子序列的情况下,本文算法只能求出一种结果,并针对这一种结果求出连续的最长公共子序列。


算法原理:设序列X={x1,x2,...,xm}和Y= {y1,y2,...,yn}的最长公共子序列为Z= {z1,z2,...,zk},则

(1)若xm=yn,则zk = xm = yn,且Zk-1是Xm-1和Yn-1的最长公共子序列;

(2)若xm!=yn,且zk!=xm,则Z是Xm-1和Y的最长公共子序列;

(3)若xm!=yn,且zk!=ym,则Z是X和Yn-1的最长公共子序列;


递归关系如下:

若i=0,j=0,则c[i][j] = 0;

若i,j>0;xi=yi,则c[i][j] = c[i-1][j-1]+1;

若i,j>0;xi!=y1,则c[i][j] = max{ c[i][j-1] , c[i-1][j] }.


算法如下:


#include <stdlib.h>
#include <iostream>
using namespace std;


int ** Create2Array(int n, int m)
{
int **s = new int*[n];
for(int i = 0;i<n;++i)
{
s[i] = new int[m];
memset(s[i],0,sizeof(int)*m);
}
return s;
}


void Delete2Array(void **p,int n,int m)
{
int **s = (int **)p;
for(int i=0;i<n;++i)
{
   delete []p[i];
}
delete []p;
}


void Print2Array(int **p,int n,int m)
{
for(int i=0; i<n; ++i)
{
for(int j=0; j<m;++j)
{
cout<<p[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}


#define XSIZE 7
#define YSIZE 6
int num = 0;
//递归查找最长公共子序列
int LcsLength(char* X,char* Y,int n,int m,int **c,int**s)
{
++num;
if(n<=0 || m<=0)
{
return 0;
}
if(c[n][m] >0) 
{
return c[n][m];
}else
{
if(X[n] == Y[m])
{
c[n][m] = 1+LcsLength(X,Y,n-1,m-1,c,s);
s[n][m] = 3;
return c[n][m];
}else
{
int max1 = LcsLength(X,Y,n,m-1,c,s);
int max2 = LcsLength(X,Y,n-1,m,c,s);
c[n][m] = max1>max2?max1:max2;
s[n][m] = max1>max2?2:1;
return c[n][m];
}
}


}
//递归打印最长子序列
void LCS(char *Y,int** s,int n,int m)
{
if(n<=0 || m<=0)
{
return;
}else
{
if(s[n][m] == 3)
{
LCS(Y,s,n-1,m-1);
cout<<Y[m]<<" ";
}else
{
if(s[n][m] == 1)
{
LCS(Y,s,n-1,m);
}else
{
LCS(Y,s,n,m-1);
}
}
}
}
//非递归求解最长公共子序列
void LcsLength3(char *X,char *Y,int n,int m,int **c,int **s)
{
for(int i=0;i<=n;++i)
{
c[0][i] = 0;
}
for(int j=0;j<=m;++j)
{
c[j][0] = 0;
}
for(int i = 1;i<=n;++i)
{
for(int j = 1;j<=m;++j)
{
if(X[i] == Y[j])
{
c[i][j] = 1+c[i-1][j-1];
s[i][j] = 3;
}else
{
c[i][j] = c[i-1][j]>c[i][j-1]?c[i-1][j]:c[i][j-1];
s[i][j] = c[i-1][j]>c[i][j-1]?1:2;
}
}
}
}
//打印连续的最长公共子序列
void MAXLCS(char*Y,int **s,int n,int m)
{
int i = m;
int j;
int max = 0;
int temp = 0;
while(n>=0 && m>=0)
{
if(s[n][m] == 3)
{
            max += 1;
i = m;
n -= 1;
m -= 1;
}else
{
if(s[n][m] == 1)
   n -= 1;
else
m -= 1;

if(temp<max)
{
temp = max;
j = i;
}
max = 0;
}
}
for(int k=j;k<temp+j;++k)
{
cout<<Y[k]<<" ";
}
cout<<endl;
}


int LcsLength2(char* X,char* Y,int n,int m)
{
++num;
if(n<=0 || m<=0 || n>XSIZE ||m>YSIZE)
{
return 0;
}else
{
if(X[n] == Y[m])
{
return 1+LcsLength2(X,Y,n+1,m+1);
}else
{
int max1 = LcsLength2(X,Y,n,m+1);
int max2 = LcsLength2(X,Y,n+1,m);
return max1>max2?max1:max2;
}
}


}


int main()
{
char X[XSIZE+2] = {"#ABCBDAB"};
char Y[YSIZE+2] = {"#BDCABA"};
int **c = Create2Array(XSIZE+1,YSIZE+1);
int **s = Create2Array(XSIZE+1,YSIZE+1);
//Print2Array(c,XSIZE+1,YSIZE+1);
int max = LcsLength(X,Y,XSIZE,YSIZE,c,s);
//int max = LcsLength2(X,Y,1,1);
        //LcsLength3(X,Y,XSIZE,YSIZE,c,s);
Print2Array(c,XSIZE+1,YSIZE+1);
Print2Array(s,XSIZE+1,YSIZE+1);
cout<<max<<endl;
//cout<<num<<endl;
LCS(Y,s,XSIZE,YSIZE);
        cout<<endl;
MAXLCS(Y,s,XSIZE,YSIZE);

return 0;
}

0 0
原创粉丝点击