刚刷的这道题是属于比较经典的LCS问题,当然该题不属于 lettcode 上面的,下面就和大家分享一下经验吧!
题目如下:
给定连个序列X与Y:
X = <x1,x2,...,xn>
Y = <y1,y2,...,ym>
找两个递增的下标序列
<i1, i2, ...ik> 和 <j1, j2, ..., jk> 使得
x(i1) == y(j1)
x(i2) == y(j2)
......
x(ik) == y(jk)
令Z = <x(i1/j1), x(i2/j2),..., x(ik/jk)>,那么称Z是X和Y的一个公共子序列。
Longest Common Subsequence(LCS问题)即是求最长的公共子序列,
题意分析:
在所有公共子序列 Z 中找到最长的公共子序列。
方法一(动态规划法)
该问题的状态转移方程如下:
维护一个二维数组 memo,memo[i][j] 表示以第 S1[i] 与 S2[j] 字母结尾的最长公共子序列的长度,根据状态转移方程,不断判断当前数字与其之前数字的大小关系,进而更新 memo 数组,最后将 memo[m-1][n-1] 返回即可。
解题代码如下:
#include <iostream>
#include <vector>
using namespace std;
class Solution{
public:
int LongestCommonSequence(string s1, string s2)
{
int n = s1.size();
int m = s2.size();
vector<vector<int>> memo( n+1, vector<int>( m+1, 0 ) );
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s1[i-1] == s2[j-1]) {
memo[i][j] = memo[i-1][j-1] + 1;
}
else {
memo[i][j] = max(memo[i][j-1], memo[i-1][j]);
}
}
}
return memo[n][m];
}
};
int main()
{
string s1;
string s2;
cin >> s1;
cin >> s2;
cout << Solution().LongestCommonSequence(s1, s2);
return 0;
}
运行结果如下:
方法二(记忆化搜索法)
该方法的递归树如下图所示,用一个二维的 memo 数组记录计算的中间结果,以避免重复计算重叠子问题,进而优化算法的时间复杂度。
解题代码如下:
#include <iostream>
#include <vector>
using namespace std;
class Solution{
vector<vector<int>> memo;
private:
int n;
int m;
int res;
int findLongestCommonSequence( string s1, int s1_index, string s2, int s2_index ){
if ( s1_index < 0 || s2_index < 0 ) return res;
if ( memo[s1_index][s2_index] != -1 ) return memo[s1_index][s2_index];
if ( s1[s1_index] == s2[s2_index] ) {
memo[s1_index][s2_index] = 1 + max(res, findLongestCommonSequence( s1, s1_index - 1, s2, s2_index - 1 ));
return memo[s1_index][s2_index];
}
else {
memo[s1_index][s2_index] = max( findLongestCommonSequence( s1, s1_index - 1, s2, s2_index ), findLongestCommonSequence( s1, s1_index, s2, s2_index - 1 ));
return memo[s1_index][s2_index];
}
}
public:
int LongestCommonSequence(string s1, string s2)
{
n = s1.size();
m = s2.size();
memo = vector<vector<int>>( n+1, vector<int>( m+1, -1 ) );
res = 0;
return findLongestCommonSequence(s1, n-1, s2, m-1);
}
};
int main()
{
string s1;
string s2;
cin >> s1;
cin >> s2;
cout << Solution().LongestCommonSequence(s1, s2);
return 0;
}
运行结果如下:
日积月累,与君共进,增增小结,未完待续。