思路:
题目的主要信息:
- 仅存在一个最长公共子序列,不需要去重
- 最长公共子序列为空需要返回"-1",而不是空序列,最后要变换
我们以dp[i][j]表示在s1中以i结尾,s2中以j结尾的字符串的最长公共子序列长度,若是i与j相等,则该问题可以变成1+dp[i][j],即最长公共子序列长度加1,若是不相等,则换成两个子问题:dp[i][j-1]或者dp[i-1][j],由此用递归即可以解决。 但是递归的复杂度过高,重复计算了太多部分,因此可以用动态规划,从前往后加: 方法一:动态规划 具体做法: 可以用二维矩阵dp记录在s1中以i结尾,s2中以j结尾的字符串的最长公共子序列长度,由此形成一个表,表从1开始往后相加。因最后要返回该序列,所以在构造表的同时要以另一个二维矩阵记录打印方向。
class Solution {
public:
string x = "";
string y = "";
string ans(int i, int j, vector<vector<int>>& b){
string res = "";
if(i == 0 || j == 0)///递归终止条件
return res;
if(b[i][j] == 1)
{
res += ans(i - 1, j - 1, b);
res += x[i - 1];
}
else if(b[i][j] == 2)
{
res += ans(i - 1, j, b);
}
else if(b[i][j] == 3)
{
res += ans(i,j - 1, b);
}
return res;
}
string LCS(string s1, string s2) {
if(s1.length() == 0 || s2.length() == 0)
return "-1";
int len1 = s1.length();
int len2 = s2.length();
x = s1;
y = s2;
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
vector<vector<int>> b(len1 + 1, vector<int>(len2 + 1, 0));
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(s1[i - 1] == s2[j - 1])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
b[i][j] = 1;///来自于左上方
}
else
{
if(dp[i - 1][j] > dp[i][j - 1])
{
dp[i][j] = dp[i - 1][j];
b[i][j] = 2;///来自于左方
}
else
{
dp[i][j] = dp[i][j - 1];
b[i][j] = 3;///来自于上方
}
}
}
}
return ans(len1, len2, b) != "" ? ans(len1, len2, b) : "-1";
}
};
复杂度分析:
- 时间复杂度:O(n^2),构造辅助数组dp与b,两层循环
- 空间复杂度:O(n^2),辅助二维数组dp与递归
方法二:栈 能够递归解决的也可以用栈解决的。 具体做法: 不需要第二个辅助数组b,直接每次比较dp与其左、上、左上的关系,然后将符合要求的字符加入栈中即可实现逆序输出。
class Solution {
public:
string LCS(string s1, string s2) {
if(s1.length() == 0 || s2.length() == 0) //只要有一个空字符串便不会有子序列
return "-1";
int len1 = s1.length();
int len2 = s2.length();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0)); //记录最长长度
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(s1[i - 1] == s2[j -1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
int i=len1, j=len2;
stack<char> s;
while(dp[i][j])
{
if(dp[i][j] == dp[i - 1][j])///来自于左方向
i--;
else if(dp[i][j] == dp[i][j - 1])///来自于上方向
j--;
else if(dp[i][j]>dp[i-1][j-1])///来自于左上方向
{
i--;
j--;
s.push(s1[i]); //入栈,逆序使用
}
}
string res = "";
while(!s.empty())
{
res += s.top();
s.pop();
}
return res != "" ? res : "-1"; //如果两个完全不同,返回字符串为空,则要改成-1
}
};
复杂度分析:
- 时间复杂度:O(n^2),构造辅助数组dp两层循环
- 空间复杂度:O(n^2),辅助二维数组dp与栈空间