找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。
cnblogs与belong,最长公共子序列为blog(cnblogs, belong),最长公共子串为lo(cnblogs, belong)
这两个问题都是用空间换空间,创建一个二维数组来记录之前的每个状态.
最长公共子序列的状态转移方程:
分析参考:https://www.cnblogs.com/en-heng/p/3963803.html
https://blog.csdn.net/ten_sory/article/details/79798064
这是经典的动态规划题目。
假设字符串 A=<x1,x2,⋯,xm> , B=<y1,y2,⋯,yn>
定义子问题dp[ i ][ j ]为字符串A的第一个字符到第 i 个(实际下标i-1)字符形成的字符串,即<x1,x2,⋯,xi>和字符串B的第一个字符到第 j(实际下标j-1) 个字符形成的字符串,即<y1,y2,⋯,yj>的最长公共子序列。
如A为“app”,B为“apple”,dp[ 2 ][ 3 ]表示 “ap” 和 “app” 的最长公共字串。注意到代码中 dp 的大小为 (n + 1) x (m + 1) ,这多出来的一行和一列是第 0 行和第 0 列,初始化为 0,表示空字符串和另一字符串的子串的最长公共子序列,例如dp[ 0 ][ 3 ]表示 “” 和 “app” 的最长公共字串。
当我们要求dp[ i ][ j ],我们要先判断A[ i-1 ]和B[ j-1 ]是否相同,如果相同他就是dp[ i - 1 ][ j - 1 ] + 1,相当于在两个字符串都去掉一个字符时的最长公共字串再加 1;否则最长公共字串取dp[ i ][ j - 1 ] 和dp[ i - 1 ][ j ] 中较大者。
class LCS {
public:
int findLCS(string A, int n, string B, int m) {
if(n<=0 || m<=0)
return 0;
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++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[n][m];
}
};
附加一个打印其中一个最长公共子序列的代码
附加: 输出其中一个最长公共子序列
// 还原如何求解dp的过程,具体看左神的p222
string solve(vector<vector<int>> &dp,n,m,string str1){
char * res = new char[dp[n][m]];
int index = dp[n][m]-1;
while(index>=0){
if(n>0 && dp[n][m]==dp[n-1][m]){
--n;
}else if(m>0 && dp[n][m]==dp[n][m-1]){
--m;
} else{
res[index]=str1[n];
--m;
--n;
}
}
string str = res;
delete[] res;
return str;
}