动态规划--最长公共子序列

描述:找出两个字符串的最长公共子序列,例如串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,则:

  1. 如果X== Yn, 那么 Zk = Xm = Yn, 而且 Zk-1 是 Xm-1 和 Yn-1 的一个LCS.
  2. 如果Xm != Yn, 那么 Zk != X蕴含 Z 是 Xm-1 和 Y 的一个LCS.
  3. 如果X!= Yn, 那么 Zk != Y蕴含 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 }

 

posted @ 2014-09-05 10:57  寂寞尘埃  阅读(144)  评论(0)    收藏  举报