本题和昨天的最大重复子串问题很相似,只不过本题不一定是连续的。
动规五部曲分析如下:
dp[i][j]:长度为i-1 的字符串text1与长度为j-1的字符串text2的最长公共子序列长度为dp[i][j]
定义为i -1 或 j-1 是为了代码实现方便
2.确定递推公式
主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[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][j] = max(dp[i - 1][j], dp[i][j - 1]);
代码如下:
if (text1[i - 1] == text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
3.dp数组如何初始化
统一初始为0。
代码:
vector> dp(text1.size() + 1, vector(text2.size() + 1, 0));
4.确定遍历顺序
从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:
那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵
5.举例推导dp数组以输入:text1 = "abcde", text2 = "ace" 为例,dp状态如图:
最后红框dp[text1.size()][text2.size()]为最终结果
第二题和第一题完全是一模一样的两题。只是换了个说法。
class Solution {
public:
int maxUncrossedLines(vector& nums1, vector& nums2) {
vector> dp(nums1.size() + 1, vector(nums2.size() + 1, 0));
for (int i = 1; i <= nums1.size(); i++) {
for (int j = 1; j <= nums2.size(); j++) {
if (nums1[i - 1] == nums2[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[nums1.size()][nums2.size()];
}
};
动规五部曲如下:
dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]。
2.确定递推公式
dp[i]只有两个方向可以推出来:
一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);
3.dp数组如何初始化
dp[0] = nums[0]。
4.确定遍历顺序
递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。
5.举例推导dp数组
以示例一为例,输入:nums = [-2,1,-3,4,-1,2,1,-5,4],对应的dp状态如下:
我们要找最大的连续子序列,就应该找每一个i为终点的连续最大子序列。
int maxSubArray(vector& nums) {
if(nums.size()<=1)return nums[0];
vector dp(nums.size(),0);
dp[0] = nums[0];
int result = dp[0];
for (int i = 1; i < nums.size(); i++) {
if(dp[i-1]+nums[i]>0){
dp[i] =max(dp[i-1]+nums[i],nums[i]);
}else{
dp[i] = nums[i];
}
if(result < dp[i])result = dp[i];
}
return result;
}
多总结题型,多看题型。多练习。继续加油!