1143.最长公共子序列
题目链接:1143.最长公共子序列
dp
数组:[0, i - 1]
和[0, j - 1]
范围的最长公共子序列表示为dp[i][j]
递推公式:
dp[i][j] = (text1[i - 1] == text2[j - 1])
? dp[i - 1][j - 1] + 1
: max(dp[i - 1][j], dp[i][j - 1]);
如果text1[i - 1]
与 text2[j - 1]
相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
如果text1[i - 1]
与 text2[j - 1]
不相同,那就看看text1[0, i - 2]
与text2[0, j - 1]
的最长公共子序列 和 text1[0, i - 1]
与text2[0, j - 2]
的最长公共子序列,取最大的。
初始化:
dp[i][0] = dp[0][j] = 0
,其他都是0
根据递推公式可知,dp[i][j]
都是之前的状态dp[i-1][j-1]
、dp[i-1][j]
、dp[i][j-1]
推出的,因此最终输出dp.back().back()
即可
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
for (int i = 1; i <= text1.size(); ++i) {
for (int j = 1; j <= text2.size(); ++j) {
dp[i][j] = (text1[i - 1] == text2[j - 1])
? dp[i - 1][j - 1] + 1
: max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp.back().back();
}
};
一维数组
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
vector<int> dp(text2.size() + 1, 0);
for (int i = 1; i <= text1.size(); ++i) {
int prev = 0;
for (int j = 1; j <= text2.size(); ++j) {
int temp = dp[j];
dp[j] = (text1[i - 1] == text2[j - 1])
? prev + 1
: max(dp[j], dp[j - 1]);
prev = temp;
}
}
return dp.back();
}
};
对代码进行进一步解释:
-
首先,创建一个大小为
text2.size() + 1
的整数型向量dp
,并将所有元素初始化为0。dp
向量用来保存子问题的最优解。 -
接下来,通过两层嵌套循环来计算最长公共子序列的长度。外层循环遍历
text1
字符串的每一个字符,内层循环遍历text2
字符串的每一个字符。 -
在外层循环的每一次迭代中,初始化变量
prev
为0。prev
用来保存上一次内层循环中dp
向量的值,即上一个元素的对角线的值。 -
在内层循环的每一次迭代中,首先保存
dp[j]
到变量temp
中。 -
然后,判断
text1[i - 1]
和text2[j - 1]
是否相等。如果相等,说明两个字符可以构成公共子序列的一部分,所以最长公共子序列的长度为prev + 1
,并将该值保存到dp[j]
中。如果不相等,则最长公共子序列的长度为dp[j]
和dp[j - 1]
中的较大值,再将该值保存到dp[j]
中。 -
最后,将
temp
的值赋给prev
,以备下一次迭代使用。 -
循环结束后,
dp.back()
表示dp
向量中最后一个元素的值,即最长公共子序列的长度。最后,将该值作为函数的返回值。
1035.不相交的线
题目链接:1035.不相交的线
相同数字连线就是数字顺序问题,就是子序列。因此和上一题代码思路一样。
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
for (int i = 1; i <= nums1.size(); ++i) {
for (int j = 1; j <= nums2.size(); ++j) {
dp[i][j] = (nums1[i - 1] == nums2[j - 1])
? dp[i - 1][j - 1] + 1
: max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp.back().back();
}
};
53. 最大子序和
题目链接:53. 最大子序和
dp
数组:以i
结尾的最大连续子序列和
递推公式:
dp[i] = max(dp[i - 1] + nums[i], nums[i])
初始化:
dp[0] = nums[0]
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> dp(nums.size(), nums[0]);
int res = nums[0];//保存为nums.size() == 1时的结果。
for (int i = 1; i < nums.size(); ++i) {
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
res = max(res, dp[i]);
}
return res;
}
};