动态规划--最长公共子序列
描述:找出两个字符串的最长公共子序列,例如串X = <A, B, C, B, D, A, B>,Y = <B, D, C, A, B, A>,则<B, C>可以算一个公共子序列,但不是最长的,最长的公共子序列为<B, C, A, B>.
算法分析,设序列X = <X1, X2, ..., Xm>, Y= <Y1, Y2, ..., Yn>. 设Z = <Z1, Z2, ..., Zk>是X和Y的任意一个LCS,则:
- 如果Xm == Yn, 那么 Zk = Xm = Yn, 而且 Zk-1 是 Xm-1 和 Yn-1 的一个LCS.
- 如果Xm != Yn, 那么 Zk != Xm 蕴含 Z 是 Xm-1 和 Y 的一个LCS.
- 如果Xm != Yn, 那么 Zk != Yn 蕴含 Z 是 Yn-1 和 X 的一个LCS.
上述特征说明,两个序列的一个LCS也包含了两个序列的前缀的一个LCS,这说明LCS问题就有最优子结构性质。
那么可以得到递归式:

又递归式可以看出该问题有重复子问题性质,由于为了找 X 和 Y 的一个LCS,可能会求 X 和 Yn-1 或者是 Xm-1 和 Y 的LCS, 儿这两个子问题又包含找 Xm-1 和 Yn-1的LCS。
由此我们可以写递归代码来求LCS长度,代码如下:
1 // LCS.cpp : 定义控制台应用程序的入口点。 2 3 #include <iostream> 4 #include <math.h> 5 #include <string> 6 using std::string; 7 8 int max(int a, int b){ return a > b ? a : b; } 9 int LCSRecursive(const string &strX, const string &strY, const int &m, const int &n) 10 { 11 if (m == 0 || n == 0) 12 return 0; 13 if (strX[m] == strY[n]) 14 { 15 return LCSRecursive(strX, strY, m - 1, n - 1) + 1; 16 } 17 else 18 { 19 return max(LCSRecursive(strX, strY, m - 1, n), LCSRecursive(strX, strY, m, n - 1)); 20 } 21 } 22 23 24 int main(int argc, char **argv) 25 { 26 const string strX = "ABCDAB"; 27 const string strY = "BDCABA"; 28 29 int LCSLength = LCSRecursive(strX, strY, strX.size(), strY.size()); 30 31 std::cout << "The Length of the Longest common subsequence is: " << LCSLength << std::endl; 32 33 return 0; 34 }
非递归如下:
1 int LCSNoneRecursive(const string &strX, const string &strY) 2 { 3 // 是字符串从下标1开始,便于C数组计算 4 string X = " " + strX; 5 string Y = " " + strY; 6 7 int m = X.size(); 8 int n = Y.size(); 9 int **c = new int*[m]; 10 11 // 申请内存存储C数组 12 for (int i = 0; i < m; ++i) 13 c[i] = new int[n]; 14 15 for (int i = 0; i < m; ++i) 16 c[i][0] = 0; 17 18 for (int j = 0; j < n; j++) 19 c[0][j] = 0; 20 21 // 计算C数组的值 22 for (int i = 1; i < m; i++) 23 for (int j = 1; j < n; j++) 24 { 25 if (X[i] == Y[j]) 26 c[i][j] = c[i - 1][j - 1] + 1; 27 else 28 { 29 if (c[i][j - 1] >= c[i - 1][j]) 30 c[i][j] = c[i][j - 1]; 31 else 32 c[i][j] = c[i - 1][j]; 33 } 34 } 35 // 最长公共子序列长度为最右下角的元素 36 int LCSLength = c[m - 1][n - 1]; 37 for (int i = 0; i < m; i++) 38 delete c[i]; 39 delete []c; 40 return LCSLength; 41 }

浙公网安备 33010602011771号