今天的题目还是有难度的,自己AC了两道,看视频看了两道,强度不小。
1143.最长公共子序列
这道题目看视频的,昨天做了一道最长重复子数组,这道题还是想不出来怎么做。这道题的子序列可以不连续,所以dp数组的定义和最长重复子数组不一样,我总结出一个规律,如果涉及到不连续的子序列,那么dp数组的定义就是第一个数组考虑[0,i]范围内元素,第二个数组考虑[0,j]范围内元素的情况下,两个数组之间的公共最长子序列的长度为dp[i][j];如果涉及到连续的子序列,那么dp数组的定义就是,第一个数组以nums1[i]结尾,第二个数组以nums2[j]结尾的情况下,所能得到的最长公共子序列的长度。
这道题就是采取前一种定义,当遍历的两个数字相同时,dp[i][j]取决于dp[i - 1][j - 1]的状态,此时i和j都回退一步。但是如果遍历的两个数字不同时,需要对i回退一步,j回退一步这两种情况取最大值。
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
//1.确定dp[i][j]的含义:一个数组考虑[0, i - 1]范围的元素,
// 另一个数组考虑[0, j - 1]范围的元素的情况下,
// 所能获得的最长公共子序列的长度为dp[i][j]
//2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
// or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
//3.dp数组初始化 dp[0][j] = 0;
// dp[i][0] = 0;
//4.确定遍历顺序:从左往右,从上往下遍历
//5.打印数组(省略)
int m = text1.size();
int n = text2.size();
int result = 0;
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
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]);
result = max(dp[i][j], result);
}
}
return result;
}
};
1035.不相交的线
这道题和上一道题是一模一样的,代码甚至都不怎么需要改就AC了,直接贴代码。
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
//1.确定dp[i][j]的含义:一个数组考虑[0, i - 1]范围的元素,
// 另一个数组考虑[0, j - 1]范围的元素的情况下,
// 所能获得的最长公共子序列的长度为dp[i][j]
//2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
// or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
//3.dp数组初始化 dp[0][j] = 0;
// dp[i][0] = 0;
//4.确定遍历顺序:从左往右,从上往下遍历
//5.打印数组(省略)
int m = nums1.size();
int n = nums2.size();
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
int result = 0;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; 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]);
result = max(result, dp[i][j]);
}
}
return result;
}
};
53. 最大子序和
这道题目感觉核心思想还是贪心啊,贪心就是一旦总和为负数就立马丢弃,这道题的dp数组的定义是:以nums[i]结尾的最大子数组和为dp[i],递推公式为dp[i] = max(dp[i - 1] + nums[i], nums[i]);和贪心的思想一模一样啊。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//1.确定dp[i]的含义:以nums[i]结尾的最大子数组和为dp[i]
//2.确定递推公式dp[i] = max(dp[i - 1] + nums[i], nums[i]);
//3.dp数组初始化 dp[0] = nums[0];
//4.确定遍历顺序:从前往后遍历
//5.打印数组(省略)
int m = nums.size();
vector<int> dp(m);
//初始化
dp[0] = nums[0];
int result = dp[0];
for(int i = 1; i < m; i++){
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
result = max(result, dp[i]);
}
return result;
}
};
392.判断子序列
这道题就是和最长公共子序列很像啊,先按照最长公共子序列的逻辑走,然后检查dp[m][n]是否为m(最长公共子序列的长度是否等于字符串s的长度),如果相等返回true,不相等就返回false。
class Solution {
public:
bool isSubsequence(string s, string t) {
//1.确定dp[i][j]的含义:一个字符串考虑[0, i - 1]范围的元素,
// 另一个字符串考虑[0, j - 1]范围的元素的情况下,
// 所能获得的最长公共子序列的长度为dp[i][j]
//2.确定递推公式dp[i][j] = dp[i - 1][j - 1] + 1;
// or dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
//3.dp数组初始化 dp[0][j] = 0;
// dp[i][0] = 0;
//4.确定遍历顺序:从左往右,从上往下遍历
//5.打印数组(省略)
int m = s.size();
int n = t.size();
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(s[i - 1] == t[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
if(dp[m][n] == m) return true;
return false;
}
};
下班。