算法作业6 动态规划

问题描述:Given 2 sequences, X = x1,...,xm and Y = y1,...,yn, find a common subsequence whose length is maximum. Subsequence need not be consecutive, but must be in order.

程序思路:

使用递归的思路可以解决这个问题。设输入的两个子串为X[0…m - 1]和Y[0…n - 1],L(X[0…m - 1], Y[0…n - 1])为X和Y的最长公共子串长度。分两种情况:

1. 若子串最后一个字符匹配(即X[m – 1] == Y[n – 1]),则

L(X[0…m - 1], Y[0…n - 1])= 1 + L(X[0…m - 2], Y[0…n - 2])

2. 若子串最后一个字符不匹配(即X[m – 1] != Y[n – 1]),则

L(X[0…m - 1], Y[0…n - 1]) = Max( L(X[0…m - 2], Y[0…n - 1]), L(X[0…m - 1], Y[0…n - 2]))

但是递归的情况下,很多子情况会重复计算多次,因此可以使用动态规划来优化,这里可以使用画表格的方法来记录下子问题的解,供后面计算使用。这里的表格记录最长公共子串的长度。

例如:”ABCFGR” 和”ACKWGR”的最长公共子串表为

右下角的值就是两个子串的最长公共子串长度。

如果需要输出两个子串的最长公共子串,则需要额外的空间把每个字符存起来。步骤如下:

  1. 构造最长公共子串长度表L[][];
  2. 构造一个长为L[m][n]的string s;
  3. 从L[m][n]这个位置开始遍历L[][],直到m或者n为0,对于L[][]中的每个元素L[i][j],

a)    若X[i - 1] == Y[j - 1],即这个字符是最长公共子串的一个字符,放在s的末尾,往左上方移动一格,即i – 1,j – 1,继续遍历。

b)    若不等,则在表格左边或者上方选择一个较大值,移动一格,即i – 1或者j – 1,继续遍历。

根据上面的例子,给出遍历路径:

所以”ABCFGR” 和”ACKWGR”的最长公共子串为”ACGR”。

算法伪代码:

 1 //LCS算法
 2 //输入:子串X,子串Y,X的长度m,Y的长度n
 3 //输出:最长公共子串
 4 LCS(X[], Y[], m, n)
 5 Begin
 6 Create L[m + 1][n + 1]
 7 for each i from 0 to m do
 8        for each j from 0 to n do
 9               if i == 0 or j == 0
10                      L[i][j] = 0
11               Else if X[i – 1] == Y[j – 1]
12                      L[i][j] = L[i – 1][j – 1] + 1
13               Else
14                      L[i][j] = max(L[i – 1][j], L[i][j – 1])
15 Create char c[L[m][n]]
16 For L[m][n] to L[0][p] or L[q][0]
17        If X[i - 1] == Y[j – 1]
18               Push this char to c
19               Skip to left up
20        Else
21               Skip to left or up which is larger
22 End

算法性能分析:

这个算法主要做的事情是,建立最长公共子串表,然后遍历这个表。表的建立需要一个一个填写表项,因此复杂度为O(mn)。

补充一下,之前一直没有考虑最长公共子串不唯一的问题。我们的算法的确能够找到一个最长公共子串,但是如果要把所有的串输出,在步骤二中必须分情况讨论,把中间结果压栈,具体细节有空再补充。

原文地址:https://www.cnblogs.com/banyu/p/4987921.html