一、问题描述
最长公共子序列(longest common sequence)。什么是子序列呢?即一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。子序列每个元素的下标严格递增。
如上图,给定的字符序列: {a,b,c,d,e,f,g,h},它的子序列示例: {a,c,e,f} 即元素b,d,g,h被去掉后,保持原有的元素序列所得到的结果就是子序列。同理,{a,h},{c,d,e}等都是它的子序列。
最长公共子序列(以下都简称LCS)即给定序列s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2},s1和s2的相同子序列,且该子序列的长度最长,即是LCS。s1和s2的其中一个最长公共子序列是 {3,4,6,7,8}
二、问题分析
1.最优子结构:设有序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},它们的最长公共子序列是Z={z1,z2,…zk},则:
①若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列;
②若xm!=yn,且zk!=xm,则Z是Xm-1和Y的最长公共子序列;
③若xm!=yn,且zk!=yn,则Z是X和Yn-1的最长公共子序列;
扫描二维码关注公众号,回复:
1059693 查看本文章
其中Xm-1={x1,x2,…,xm-1},Yn-1={y1,y2,…,yn-1},Zk-1={z1,z2,…zk-1};
2.子问题的递归结构:c[i][j]记录序列Xi和Yj的最长公共子序列的长度;
#include <iostream> using namespace std; #define M 8 #define N 7 //序列x长度xl+1,序列y长度yl+1, //c[i][j]记录子序列Xi和Yj的最长公共子序列长度, //b[i][j]记录c[i][j]的值是由哪一个子问题得到的 void LCSLength(int xl,int yl,char x[],char y[],int c[M][N],int b[M][N]) { for(int i=0;i<xl;i++){c[i][0]=0;b[i][0]=0;} //多了一行和一排表示序列x和y都是空序列的情况 for(int i=0;i<yl;i++){c[0][i]=0;b[0][i]=0;} for(int i=1;i<xl;i++) { for(int j=1;j<yl;j++) { if(x[i-1]==y[j-1]) { c[i][j]=c[i-1][j-1]+1; b[i][j]=1; } else { c[i][j]=c[i-1][j]; int t = c[i][j-1]; if(c[i][j]<t) { c[i][j]=t; b[i][j]=2; } else b[i][j]=3; } } } } void LCS(int i,int j,char x[],int b[M][N]) { if(i==0||j==0)return; if(b[i][j]==1){ LCS(i-1,j-1,x,b); cout<<x[i-1]<<" "; } else if(b[i][j]==2)LCS(i,j-1,x,b); else LCS(i-1,j,x,b); } int main() { char x[]={'A','B','C','B','D','A','B'}, y[]={'B','D','C','A','B','A'}; int c[M][N],b[M][N]; LCSLength(M,N,x,y,c,b); for(int i=0;i<M;i++) { for(int j=0;j<N;j++) cout<<c[i][j]<<" "; cout<<endl; } LCS(M-1,N-1,x,b); }
复杂性分析:O(n^2);