问题描述:
求解两个字符串的最长公共子串
参考资料:
1、http://blog.csdn.net/yysdsyl/article/details/4226630
2、http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2764625.html
问题解决:
使用动态规划,考虑如何将原问题转换为子问题,假设字符串X形如x1 x2 x3 x4....xm
字符串Y形如y1 y2 y3...yn,考虑X和Y的最长公共子串:
若x1=y1,则原问题可以转化为求解x2 x3 x4...xm与y2 y3 y4...yn的最长公共子串
若x1!=y1,则原问题可以转换为求解x2 x3 x4...xm 与 y1 y2 y3 y4...yn 或者 x1 x2 x3 x4...xm 与y2 y3 y4...yn 的最长公共子串
现在使用二维数组c[i][j]表示字符串X[i]的前i个元素与Y[j]的前j个元素的最长公共子串长度,则有:
以字符串X="ABCBDAB" 和字符串Y="BDCABA" 为例子,生成的c[i][j]如下所示:
回溯输出字符串,使用一个二维数组b[i][j]记录c[i][j]通过哪一个子问题求得,如下:
也就是,当b[i][j]=0相当于如上图中的 左上箭头,b[i][j]=1 为如上图的向上箭头
b[i][j]=-1为如上图的向左箭头。
代码文件:
/** * 求解最长公共子序列 * 满足动态规划的条件,使用动态规划的思想求解。 * 考虑最长公共子序列问题如何分解成子问题,设X=“x0,x1,…,xm-1”,Y=“y0,y1,…,ym-1”, * 并Z=“z0,z1,…,zk-1”为它们的最长公共子序列。不难证明有以下性质: * *(1) 如果xm-1=yn-1,则zk-1=xm-1=yn-1,且“z0,z1,…,zk-2”是“x0,x1,…,xm-2”和“y0,y1,…,yn-2”的一个最长公共子序列; * *(2) 如果xm-1!=yn-1,则若zk-1!=xm-1,蕴涵“z0,z1,…,zk-1”是“x0,x1,…,xm-2”和“y0,y1,…,yn-1”的一个最长公共子序列; * *(3) 如果xm-1!=yn-1,则若zk-1!=yn-1,蕴涵“z0,z1,…,zk-1”是“x0,x1,…,xm-1”和“y0,y1,…,yn-2”的一个最长公共子序列。 * * * * 这样,在找X和Y的公共子序列时, * 如有xm-1=yn-1,则进一步解决一个子问题,找“x0,x1,…,xm-2”和“y0,y1,…,ym-2”的一个最长公共子序列; * 如果xm-1!=yn-1,则要解决两个子问题,找出“x0,x1,…,xm-2”和“y0,y1,…,yn-1”的一个最长公共子序列和 * 找出“x0,x1,…,xm-1”和“y0,y1,…,yn-2”的一个最长公共子序列,再取两者中较长者作为X和Y的最长公共子序列。 * * 引进一个二维数组c[][],用c[i][j]记录X前i个子串与Y前j个子串的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的, * 以决定搜索的方向。 * 我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。 * 此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。 * */ #include <iostream> using namespace std; void LCSLength(char* x,char* y,int m,int n,int** c,int** y) { for (int i=0;i<=m;i++) { c[i][0]=0; } for (int j=1;j<=n;j++) { c[0][j]=0; } 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]=0; } else if (c[i][j-1]>c[i-1][j]) { c[i][j]=c[i][j-1]; b[i][j]=-1; } else { c[i][j]=c[i-1][j]; b[i][j]=1; } } } //输出X[i]和Y[j]的最长公共子串的长度c[i][j] for (int i=0;i<=m;i++) { for (int j=0;j<=n;j++) { cout<<c[i][j]<<" "; } cout<<endl; } cout<<endl; } //回溯,输出最长公共子串 void PrintLCS(char* x,int** c,int** b,int m,int n) { if (m==0||n==0) { return ; } if (b[m][n]==0) { PrintLCS(x,c,b,m-1,n-1); cout<<x[m-1]; } else if (b[m][n]==1) { PrintLCS(x,c,b,m-1,n); } else { PrintLCS(x,c,b,m,n-1); } } int main() { char* x="ABCBDAB"; char* y="BDCABA"; int m=7; int n=6; int **c=new int*[m+1]; for (int i=0;i<=m;i++) { c[i]=new int[n+1]; } //new 二维数组 int **b=new int*[m+1]; for (int i=0;i<=m;i++) { b[i]=new int[n+1]; } LCSLength(x,y,m,n,c,b); PrintLCS(x,c,b,m,n); cout<<endl; for (int i=0;i<=m;i++) { delete []c[i]; } for (int i=0;i<=m;i++) { delete []b[i]; } }