给出两个字符串,找到最长公共子序列(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的长度,状态转移方程为
- dp[i][j] = 0 如果 i = 0或 j = 0
- dp[i][j] = dp[i - 1][j - 1] + 1 如果X[i - 1] = Y[i - 1] (X[i - 1]就是X数组中的第i个)
- 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]; } };