[LintCode] Longest Common Subsequence

给出两个字符串,找到最长公共子序列(LCS),返回LCS的长度。

说明

最长公共子序列的定义:

  • 最长公共子序列问题是在一组序列(通常2个)中找到最长公共子序列(注意:不同于子串,LCS不需要是连续的子串)。该问题是典型的计算机科学问题,是文件差异比较程序的基础,在生物信息学中也有所应用。
  • https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
样例

给出"ABCD" 和 "EDCA",这个LCS是 "A" (或 D或C),返回1

给出 "ABCD" 和 "EACB",这个LCS是"AC"返回 2

最长公共子序列是DP的典型例子。

设X = <x1, x2, x3, .. . , xm>, Y = <y1, y2, y3, ... , yn> 为两个子串。

LCS(X, Y)表示X和Y的一个最长公共子序列。则:

  1. 如果xm = yn 则 LCS(X, Y) = xm + LCS(Xm-1, Yn-1)

  2. 如果xm != yn 则 LCS(X, Y) = max{LCS(Xm-1, Y), LCS(X, Yn-1)}

LCS问题也具有重叠子问题性质:为找出X和Y的一个LCS,可能需要找X和Yn-1的一个LCS以及Xm-1和Y的一个LCS。但这两个子问题都包含着找Xm-1和Yn-1的一个LCS,等等.

DP最终处理的还是数值(极值做最优解),找到了最优值,就找到了最优方案;为了找到最长的LCS,我们定义dp[i][j]记录序列LCS的长度,合法状态的初始值为当序列X的长度为0或Y的长度为0,公共子序列LCS长度为0,即dp[i][j]=0,所以用i和j分别表示序列X的长度和序列Y的长度,状态转移方程为

  1. dp[i][j] = 0  如果 i = 0或 j = 0
  2. dp[i][j] = dp[i - 1][j - 1] + 1  如果X[i - 1] = Y[i - 1] (X[i - 1]就是X数组中的第i个)
  3. dp[i][j] = max{ dp[i - 1][j], dp[i][j - 1] }  如果X[i - 1] != Y[i - 1]
class Solution {
public:
    /*
     * @param A: A string
     * @param B: A string
     * @return: The length of longest common subsequence of A and B
     */
    int longestCommonSubsequence(string A, string B) {
        // write your code here
        int m = A.size(), n = B.size();
        if (m == 0 || n == 0)
            return 0;
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (int i = 1; i != m + 1; i++) {
            for (int j = 1; j != n + 1; j++) {
                if (A[i - 1] == B[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        return dp[m][n];
    }
};
原文地址:https://www.cnblogs.com/immjc/p/7435168.html