原题网址:https://www.lintcode.com/problem/longest-common-subsequence/description
描述
给出两个字符串,找到最长公共子序列(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【m+1】【n+1】,并初始化元素值为0。dp【i】【j】表示 A 串 0~i-1 与 B 串 0~j-1 的LCS。
状态转移方程:
固定一个字符串,遍历另一个字符串,如果A【i-1】==B【j-1】,dp【i】【j】=dp【i-1】【j-1】+1;
否则,说明 A【i-1】和 B【j-1】不可能都是最长公共子序列中的元素,所以应在A 串 0~i-1 与 B 串 0~j-2 或 A 串 0~i-2 与 B 串 0~j-1 中寻找LCS,二者中较大者即为dp【i】【j】。即 dp【i】【j】= max(dp【i】【j-1】,dp【i-1】【j】);
最后返回dp【m】【n】,A 串 0~m-1 与 B 串 0~n-1 的LCS。
【状态转移方程是递增或者不变的,所以后面位置的LCS一定大于或者等于前面位置的,所以最后一个元素一定是两个字符串的LCS最大值。】
AC代码:
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 if (A.size()==0||B.size()==0) { return 0; } int n1=A.size(),n2=B.size(); vectorint >> dp(n1+1,vector<int>(n2+1,0)); for (int i=1;i<=n1;i++)//小于等于; { for (int j=1;j<=n2;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[n1][n2]; } };
动态数组大小为A.size()+1 × B.size()+1 , dp【i】【j】表示 A 串 0~i-1 与 B 串 0~j-1 的LCS 而不是 A 串 0~i 与 B 串 0~j 是为了计算方便,如果是后者,需要先计算dp数组的第一行和第一列,代码复杂度增加。
参考:
经典算法——最长公共子序列 与 求解两个字符串的最长公共子序列 讲解详细易懂
其中链接2摘抄部分原文如下,并添加绿字以便更好的理解:
二,算法求解
这是一个动态规划的题目。对于可用动态规划求解的问题,一般有两个特征:①最优子结构;②重叠子问题
①最优子结构
设 X=(x1,x2,.....xn) 和 Y={y1,y2,.....ym} 是两个序列,将 X 和 Y 的最长公共子序列记为LCS(X,Y)
找出LCS(X,Y)就是一个最优化问题。因为,我们需要找到X 和 Y中最长的那个公共子序列。而要找X 和 Y的LCS,首先考虑X的最后一个元素和Y的最后一个元素。
1)如果 xn=ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)
LCS(Xn-1,Ym-1)就是原问题的一个子问题。为什么叫子问题?因为它的规模比原问题小。(小一个元素也是小嘛....)
为什么是最优的子问题?因为我们要找的是Xn-1 和 Ym-1 的最长公共子序列啊。。。最长的!!!换句话说,就是最优的那个。(这里的最优就是最长的意思)
2)如果xn != ym,这下要麻烦一点,因为它产生了两个子问题:LCS(Xn-1,Ym) 和 LCS(Xn,Ym-1)
因为序列X 和 序列Y 的最后一个元素不相等嘛,那说明最后一个元素不可能都是最长公共子序列中的元素嘛。(都不相等了,怎么公共嘛)。
LCS(Xn-1,Ym)表示:最长公共序列可以在(x1,x2,....x(n-1)) 和 (y1,y2,...yn)中找。
LCS(Xn,Ym-1)表示:最长公共序列可以在(x1,x2,....xn) 和 (y1,y2,...y(n-1))中找。
求解上面两个子问题,得到的公共子序列谁最长,那谁就是 LCS(X,Y)。用数学表示就是:
LCS=max{LCS(Xn-1,Ym),LCS(Xn,Ym-1)}
由于条件 1) 和 2) 考虑到了所有可能的情况。因此,我们成功地把原问题 转化 成了 三个规模更小的子问题。
动态规划基础篇之最长公共子序列问题
最长公共子序列
https://blog.csdn.net/ljlstart/article/details/48350223
PS:最开始想到了动态规划,然而动态规划数组定义成了一维,还思考了半天怎么计算状态转移方程,用两个字符变量保存字符串上一次相等时的值……后来当然是做不下去了。看了网上答案,要用二维数组,顿时恍然大悟,这种求两个串公共字符的问题当然是二维数组了,题目做的还是不够多,反应不过来。