力扣刷题DAY10(动态规划-线性DP)
一、最长公共子序列
1143. 最长公共子序列
(一)灵茶山艾府
最长公共子序列 编辑距离【基础算法精讲 19】
定义:D[i][j]表示text1的前i个字符和text2的前j个字符的LCS。
然后需要考虑两个问题:
因此得到递推式:
(二)邋遢大哥233
[轻松掌握动态规划]5.最长公共子序列 LCS
最终代码:
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n = text1.size();
int m = text2.size();
vector<vector<int>> f(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (text1[i - 1] == text2[j - 1])
f[i][j] = f[i - 1][j - 1] + 1;
else
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
return f[n][m];
}
};
复杂度分析
- 时间复杂度:O(nm)。
- 空间复杂度:O(nm)。
降维后(滚动数组):
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n = text1.size();
int m = text2.size();
vector<int> f(m + 1, 0);
for (int i = 1; i <= n; i++) {
int temp = 0; // 保存f[i-1][j-1]
for (int j = 1; j <= m; j++) {
int pre = f[j]; // 保存这一行的f[j]方便作为左上角
if (text1[i - 1] == text2[j - 1])
f[j] = temp + 1;
else
f[j] = max(f[j], f[j - 1]);
temp = pre; // 成为下一行的左上角
}
}
return f[m];
}
};
复杂度分析
- 时间复杂度:O(nm)。
- 空间复杂度:O(m)。
二、编辑距离
72. 编辑距离
代码:
class Solution {
public:
int minDistance(string word1, string word2) {
int n = word1.size();
int m = word2.size();
vector<vector<int>> f(n + 1, vector<int>(m + 1, 0));
for (int i = 0; i <= m; i++)
f[0][i] = i;
for (int i = 0; i <= n; i++)
f[i][0] = i;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (word1[i - 1] != word2[j - 1])
f[i][j] =
min(min(f[i - 1][j], f[i][j - 1]), f[i - 1][j - 1]) + 1;
else
f[i][j] = f[i - 1][j - 1];
}
}
return f[n][m];
}
};
复杂度分析
- 时间复杂度:O(nm),其中 n 为 s 的长度,m 为 t 的长度。
- 空间复杂度:O(nm)。
降维后(滚动数组):
class Solution {
public:
int minDistance(string word1, string word2) {
int n = word1.size();
int m = word2.size();
vector<int> f(m + 1, 0);
for (int i = 0; i <= m; i++)
f[i] = i;
for (int i = 1; i <= n; i++) {
int pre = f[0]; // pre 保存 f[i-1][j-1],初始为 f[i-1][0] = i-1
f[0] = i; // 更新当前行的 f[i][0] = i
for (int j = 1; j <= m; j++) {
int temp = f[j]; // 保存本次f[j],方便保留为左上角
if (word1[i - 1] != word2[j - 1])
f[j] = min(min(f[j], f[j - 1]), pre) + 1;
else
f[j] = pre;
pre = temp; // pre成为左上角
}
}
return f[m];
}
};
易错点:
int pre = f[0]; // pre 保存 f[i-1][j-1],初始为 f[i-1][0] = i-1
f[0] = i; // 更新当前行的 f[i][0] = i
- 降维后,每行的f[0](最左边一列)也是要随时更新的。
- 而pre要履行它的职责就是保存左上角的数,而对于每一行刚开始的时候,就是保存f[0]。
复杂度分析
- 时间复杂度:O(nm)。
- 空间复杂度:O(m)。