您的位置:首页 > 其它

最长公共子序列LCS和最长单调递增子序列

2011-12-12 17:54 369 查看

0x0    最长公共子序列LCS

【开篇案例】

序列:X={A,B,C,B,D,A,B}

序列:Y={B,C,D,B,A}

序列:Z={B,C,D,B}

序列:W={B,C,D}

Z是(X与Y)的最长公共子序列(Longest-Common-Subsequence),而W虽然是X与Y的公共子序列,但是不是最长的!

【晦涩定义】

给定一个序列X={x1,x2,x3...xm},另一个序列Z={z1,z2,z3...zk}为子序列,如果存在X的

一个严格递增下标序列<i1,i2,i3,i4...ik>,使得所有的j=1,2,...,k,有x[i<j>]=z[j]

例如,Z={B,C,D,B}是X={A,B,C,B,D,A,B}一个最长子序列,相应的下标序列为<2,3,5,7>

如果Z同时是Y的最长子序列,那么Z就是X与Y的最长公共子序列

【应用场景】

生物基因的两条螺旋链的相似度,公共子序列越长,越相似!(Z=X=Y的时候,可以说两条螺旋链完全相同!)

【最优子结构性质】

特征1、如果xm==yn,那么zk == xm == yn ,而且Zk-1是(Xk-1与Yk-1)的一个LCS

特征2、如果xm != yn,那么zk !=xm,推出:Z是(Xm-1和Y)的一个LCS

特征3、如果xm != yn,那么zk !=yn,推出:Z是(X与Yn-1)的一个LCS

这三条特征说明两个序列(X与Y)的LCS,包含这两个序列前缀(Xm-1与Yn 或 Xm与Yn-1 ...)的LCS,

也就是说,LCS具备最优子结构性质!

【递归解性质】

1.xm == yn,那么把xm==yn加入到这个LCS中就得到X,Y的LCS

2.xm!=yn,那么找到(Xm-1与Yn)的一个LCS,和(X与Yn-1)的一个LCS,比较哪个更长取之为XY的一个LCS

这两点可以看出,这个LCS有递归解!

【动态规划】

既满足了最优子结构,又满足了递归解,我们很容易就想到了用动态规划来实现!

定义C[i,j]为Xi,Yj的一个LCS长度!

C[i,j]={  0 ,              i ==0 || j == 0

  c[i-1,j-1]+1 ,              i,j>0 && xi == yj

 max(c[i,j-1],c[i-1,j])          i,j>0  && xi != yj     }

【LCS-Length算法】

LCS-LENGTH(X,Y)
m = length[X]
n = length[Y]
for i= 1 to m
do c[i,0] = 0
for j =1 to n
do c[0,j] = 0
for i =1 to m
do for j=1 to n
do if xi == yj	then
c[i,j] = c[i-1,j-1]+1
b[i,j] = 1
else if c[i-1,j] >= c[i,j-1] then
c[i,j] =c[i-1,j]
b[i,j] = 2
else then
c[i,j] = c[i,j-1]
b[i,j] = 3
return c and b


【LCS构造算法】

b[i,j] == 1 表示xi == yi是LCS的一个元素

b[i,j] == 2 表示LCS选择的是c[i-1,j]

b[i,j] == 3 表示LCS选择的是c[i,j-1]

PRINT-LCS(b,X,i,j)
if i == 0 || j == 0  then
return
if b[i,j] == 1  then
PRINT-LCS(b,X,i-1,j-1)
print xi
else if b[i,j] == 2 then
PRINT-LCS(b,X,i-1,j)
else then
PRINT-LCS(b,X,i,j-1)


【C++代码】

       

#include <iostream>
#define length 7
using namespace std;

int c[length+1][length+1],b[length+1][length+1];
int x_length;
int y_length;

void Length_LCS(int x[],int y[])
{
int m=x_length;
int n=y_length;
for (int i=0; i<=m; i++)
{
c[i][0] = 0;
}
for(int j=0; j<=n; j++)
{
c[0][j] =0;
}
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
if(x[i] == y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
}

void print_LCS(int b[length+1][length+1],int X[length+1],int i,int j)
{
if( i== 0|| j ==0)  return ;
if(b[i][j] == 1)
{
print_LCS(b,X,i-1,j-1);
cout<<X[i]<<" ";
}
else if(b[i][j] == 2)
{
print_LCS(b,X,i-1,j);
}
else
{
print_LCS(b,X,i,j-1);
}

}

int main()
{
int X[]= {0,1,2,3,2,4,1,2};
int Y[]= {0,2,4,3,1,2,1};
x_length=7;
y_length=6;
cout<<"This is to test the LCS by ouyang!"<<endl;
Length_LCS(X,Y);
print_LCS(b,X,x_length,y_length);
return 0;

}


 

0x1    最长单调递增子序列

【与最长公共子序列的关系】

序列X与排完序的X'的最长公共子序列 == 最长单调递增子序列!

重点:排完序的自己!

【C++代码】

#include <iostream>

using namespace std;

void Exchange(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}

int Position(int a[],int p,int r)
{
int t=a[r];
int i=p-1;
bool flag =true;
for(int j=p;j<=r-1;j++)
{
if(a[j]!=t)
{
flag=false;
}
if(a[j] <= t)
{
i++;
Exchange(&a[j],&a[i]);
}
}
Exchange(&a[i+1],&a[r]);
if(!flag) return i+1;
else return (p+r)/2;
}

void QuickSort(int a[],int p,int r)
{
if(p < r)
{
int q=Position(a,p,r);
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
}
}

#define length  7
int c[length+1][length+1],b[length+1][length+1];
int x_length;
int y_length;

void Length_LCS(int x[],int y[])
{
int m=x_length;
int n=y_length;
for (int i=0; i<=m; i++)
{
c[i][0] = 0;
}
for(int j=0; j<=n; j++)
{
c[0][j] =0;
}
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
if(x[i] == y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else if(c[i-1][j] >= c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
}

void print_LCS(int b[length+1][length+1],int X[length+1],int i,int j)
{
if( i== 0|| j ==0)  return ;
if(b[i][j] == 1)
{
print_LCS(b,X,i-1,j-1);
cout<<X[i]<<" ";
}
else if(b[i][j] == 2)
{
print_LCS(b,X,i-1,j);
}
else
{
print_LCS(b,X,i,j-1);
}

}

int main()
{
cout<<"This is to test the 最长子序列 by ouyang!"<<endl;
int X[]= {NULL,1,2,3,2,4,1,2};
int Y[]= {NULL,1,2,3,2,4,1,2};
x_length=7;
y_length=7;
QuickSort(Y,1,7);
Length_LCS(X,Y);
print_LCS(b,X,x_length,y_length);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  zk c 算法