最长公共子序列(LCS)
2012-08-20 20:50
183 查看
先介绍LCS问题的性质:记Xm={x0, x1,…xm-1}和Yn={y0,y1,…,yn-1}为两个字符串,而Zk={z0,z1,…zk-1}是它们的LCS,则:
1. 如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的LCS;
2. 如果xm-1≠yn-1,那么当zk-1≠xm-1时Z是Xm-1和Y的LCS;
3. 如果xm-1≠yn-1,那么当zk-1≠yn-1时Z是Yn-1和X的LCS;
下面简单证明一下这些性质:
1. 如果zk-1≠xm-1,那么我们可以把xm-1(yn-1)加到Z中得到Z’,这样就得到X和Y的一个长度为k+1的公共子串Z’。这就与长度为k的Z是X和Y的LCS相矛盾了。因此一定有zk-1=xm-1=yn-1。
既然zk-1=xm-1=yn-1,那如果我们删除zk-1(xm-1、yn-1)得到的Zk-1,Xm-1和Yn-1,显然Zk-1是Xm-1和Yn-1的一个公共子串,现在我们证明Zk-1是Xm-1和Yn-1的LCS。用反证法不难证明。假设有Xm-1和Yn-1有一个长度超过k-1的公共子串W,那么我们把加到W中得到W’,那W’就是X和Y的公共子串,并且长度超过k,这就和已知条件相矛盾了。
2. 还是用反证法证明。假设Z不是Xm-1和Y的LCS,则存在一个长度超过k的W是Xm-1和Y的LCS,那W肯定也X和Y的公共子串,而已知条件中X和Y的公共子串的最大长度为k。矛盾。
3. 证明同2。
有了上面的性质,我们可以得出如下的思路:求两字符串Xm={x0,x1,…xm-1}和Yn={y0,y1,…,yn-1}的LCS,如果xm-1=yn-1,那么只需求得Xm-1和Yn-1的LCS,并在其后添加xm-1(yn-1)即可;如果xm-1≠yn-1,我们分别求得Xm-1和Y的LCS和Yn-1和X的LCS,并且这两个LCS中较长的一个为X和Y的LCS。
如果我们记字符串Xi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]:
/ 0
if i<0 or j<0
c[i,j]= c[i-1,j-1]+1 ifi,j>=0
and xi=xj
\
max(c[i,j-1],c[i-1,j] ifi,j>=0 and xi≠xj
上面的公式用递归函数不难求得。
1. 如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的LCS;
2. 如果xm-1≠yn-1,那么当zk-1≠xm-1时Z是Xm-1和Y的LCS;
3. 如果xm-1≠yn-1,那么当zk-1≠yn-1时Z是Yn-1和X的LCS;
下面简单证明一下这些性质:
1. 如果zk-1≠xm-1,那么我们可以把xm-1(yn-1)加到Z中得到Z’,这样就得到X和Y的一个长度为k+1的公共子串Z’。这就与长度为k的Z是X和Y的LCS相矛盾了。因此一定有zk-1=xm-1=yn-1。
既然zk-1=xm-1=yn-1,那如果我们删除zk-1(xm-1、yn-1)得到的Zk-1,Xm-1和Yn-1,显然Zk-1是Xm-1和Yn-1的一个公共子串,现在我们证明Zk-1是Xm-1和Yn-1的LCS。用反证法不难证明。假设有Xm-1和Yn-1有一个长度超过k-1的公共子串W,那么我们把加到W中得到W’,那W’就是X和Y的公共子串,并且长度超过k,这就和已知条件相矛盾了。
2. 还是用反证法证明。假设Z不是Xm-1和Y的LCS,则存在一个长度超过k的W是Xm-1和Y的LCS,那W肯定也X和Y的公共子串,而已知条件中X和Y的公共子串的最大长度为k。矛盾。
3. 证明同2。
有了上面的性质,我们可以得出如下的思路:求两字符串Xm={x0,x1,…xm-1}和Yn={y0,y1,…,yn-1}的LCS,如果xm-1=yn-1,那么只需求得Xm-1和Yn-1的LCS,并在其后添加xm-1(yn-1)即可;如果xm-1≠yn-1,我们分别求得Xm-1和Y的LCS和Yn-1和X的LCS,并且这两个LCS中较长的一个为X和Y的LCS。
如果我们记字符串Xi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]:
/ 0
if i<0 or j<0
c[i,j]= c[i-1,j-1]+1 ifi,j>=0
and xi=xj
\
max(c[i,j-1],c[i-1,j] ifi,j>=0 and xi≠xj
上面的公式用递归函数不难求得。
#include <string.h> #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; // directions of LCS generation enum decreaseDir { kInit = 0, kLeft, kUp, kLeftUp }; void LCS_Print(int **LCS_direction, char* pStr1, char* pStr2, size_t row, size_t col); ///////////////////////////////////////////////////////////////////////////// // Get the length of two strings' LCSs, and print one of the LCSs // Input: pStr1 - the first string // pStr2 - the second string // Output: the length of two strings' LCSs ///////////////////////////////////////////////////////////////////////////// int LCS(char* pStr1, char* pStr2) { if (!pStr1 || !pStr2) return 0; size_t length1 = strlen(pStr1); size_t length2 = strlen(pStr2); if (!length1 || !length2) return 0; size_t i, j; // initiate the length matrix int **LCS_length; LCS_length = (int**) (new int[length1]); for (i = 0; i < length1; ++i) LCS_length[i] = (int*) new int[length2]; for (i = 0; i < length1; ++i) for (j = 0; j < length2; ++j) LCS_length[i][j] = 0; // initiate the direction matrix int **LCS_direction; LCS_direction = (int**) (new int[length1]); for (i = 0; i < length1; ++i) LCS_direction[i] = (int*) new int[length2]; for (i = 0; i < length1; ++i) for (j = 0; j < length2; ++j) LCS_direction[i][j] = kInit; for (i = 0; i < length1; ++i) { for (j = 0; j < length2; ++j) { if (i == 0 || j == 0) { if (pStr1[i] == pStr2[j]) { LCS_length[i][j] = 1; LCS_direction[i][j] = kLeftUp; } else LCS_length[i][j] = 0; } // a char of LCS is found, // it comes from the left up entry in the direction matrix else if (pStr1[i] == pStr2[j]) { LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1; LCS_direction[i][j] = kLeftUp; } // it comes from the up entry in the direction matrix else if (LCS_length[i - 1][j] > LCS_length[i][j - 1]) { LCS_length[i][j] = LCS_length[i - 1][j]; LCS_direction[i][j] = kUp; } // it comes from the left entry in the direction matrix else { LCS_length[i][j] = LCS_length[i][j - 1]; LCS_direction[i][j] = kLeft; } } } LCS_Print(LCS_direction, pStr1, pStr2, length1 - 1, length2 - 1); /*for (i = 0; i < length1; i++) { printf("\n"); for (j = 0; j < length2; j++) { printf("%d%s\t", LCS_length[i][j], (LCS_direction[i][j] == kUp ? "↑" : (LCS_direction[i][j] == kLeft ? "←" : (LCS_direction[i][j] == kLeftUp ? "↖" : " ")))); } }*/ int len = LCS_length[length1 - 1][length2 - 1]; for (i = 0; i < length1; ++i) delete[] LCS_length[i]; delete[] LCS_length; return len; } ///////////////////////////////////////////////////////////////////////////// // Print a LCS for two strings // Input: LCS_direction - a 2d matrix which records the direction of // LCS generation // pStr1 - the first string // pStr2 - the second string // row - the row index in the matrix LCS_direction // col - the column index in the matrix LCS_direction ///////////////////////////////////////////////////////////////////////////// void LCS_Print(int **LCS_direction, char* pStr1, char* pStr2, size_t row, size_t col) { if (pStr1 == NULL || pStr2 == NULL) return; size_t length1 = strlen(pStr1); size_t length2 = strlen(pStr2); if (length1 == 0 || length2 == 0 || !(row < length1 && col < length2)) return; // kLeftUp implies a char in the LCS is found if (LCS_direction[row][col] == kLeftUp) { if (row > 0 && col > 0) LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col - 1); // print the char printf("%c", pStr1[row]); } else if (LCS_direction[row][col] == kLeft) { // move to the left entry in the direction matrix if (col > 0) LCS_Print(LCS_direction, pStr1, pStr2, row, col - 1); } else if (LCS_direction[row][col] == kUp) { // move to the up entry in the direction matrix if (row > 0) LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col); } } int main(void) { LCS("ABCBDAB", "BDCABA");//结果:BDAB return 0; }
相关文章推荐
- LCS最长公共子序列――动态规划
- (Relax DP1.6)UVA 10405 Longest Common Subsequence(使用DP来求解最长公共子序列LCS)
- 最长公共子序列LCS
- LCS 最长公共子序列
- 动态规划——最长公共子序列(LCS)&最长递增子序列(LIS)
- 最长公共子序列(LCS)问题
- hdu 1159 Common Subsequence_LCS(最长公共子序列)
- 最长公共子序列(LCS)问题
- LIS(最长递增子序列)和LCS(最长公共子序列)的总结
- 【LCS,LIS】最长公共子序列、单调递增最长子序列
- 求最长公共子序列——LCS
- 最长公共子序列LCS和字符串编辑距离
- 最长公共子序列(LCS)
- DP---LCS 最长公共子序列问题
- LCS(最长公共子序列)
- 自顶向下动态规划解决最长公共子序列(LCS)问题
- 1006 最长公共子序列Lcs
- 最长公共子序列(LCS)
- 基于DP的LCS(最长公共子序列)问题
- 动态规划——最长公共子序列问题(LCS)