代码随想录算法训练营
Day44 代码随想录算法训练营第 44 天 |LeetCode1143.最长公共子序列 LeetCode 1035.不相交的线 LeetCode 53. 最大子序和 LeetCode392.判断子序列
目录
前言
LeetCode1143.最长公共子序列
LeetCode 1035.不相交的线
LeetCode 53. 最大子序和
LeetCode392.判断子序列
一、LeetCode1143.最长公共子序列
1.题目链接
2.思路
(1)dp[i][j] 表示字符串1[0,i] 和字符串[0,j]的最长公共子序列长度
(2)状态转移:
1)如果text1[i]==text2[j] 说明最长公共子序列延长,text1[i]和text2[j]都加入公共子序列:dp[i][j] = dp[i - 1][j - 1] + 1
2)如果text1[i] != text2[j]说明最新的元素不能同时加入加入最长公共子序列,舍去text1[i] 或者 text2[j]:
字符串1[0,i] 和字符串[0,j]的最长公共子序列长度等于[0,i][0,j-1]公共最长公共子序列的长度与 [0,i-1][0,j]公共最长公共子序列的长度的最大值
(3)初始化
如果text1[0]和text2[j]相等,那么从此以后所有的dp[0][j]都设置为1
如果text1[i]和text2[0]相等,那么从此以后所有的dp[i][0]都设置为1
3.题解
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n = text1.size();
int m = text2.size();
vector<vector<int>> dp(n, vector<int>(m, 0));
int flag = 0;
for (int i = 0; i < n; i++) {
if (text1[i] == text2[0])
flag = 1;
if (flag)
dp[i][0] = 1;
}
flag = 0;
for (int i = 0; i < m; i++) {
if (text1[0] == text2[i])
flag = 1;
if (flag)
dp[0][i] = 1;
}
for (int i = 0; i < n && i < m; i++) {
if (text1[i] == text2[i])
dp[i][i] = 1;
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (text1[i] == text2[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[n - 1][m - 1];
}
};
二、LeetCode1035.不相交的线
1.题目链接
2.思路
(1)不相交的线:
1)要求:连接两个数字 nums1[i] 和 nums2[j] 的直线,只要 nums1[i] == nums2[j],且直线不能相交
2)直线不能相交—子序列元素相对顺序不变
变成求nums1和nums2的子序列长度,并且子序列元素相对顺序不变
e.g.1 2 4和1 4 2:公共子序列为 1 2
3.题解
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
int m = nums2.size();
vector<vector<int>> dp(n, vector<int>(m, 0));
int flag = 0;
for (int i = 0; i < n; i++) {
if (nums1[i] == nums2[0])
flag = 1;
if (flag)
dp[i][0] = 1;
}
flag = 0;
for (int i = 0; i < m; i++) {
if (nums1[0] == nums2[i])
flag = 1;
if (flag)
dp[0][i] = 1;
}
for (int i = 0; i < n && i < m; i++) {
if (nums1[i] == nums2[i])
dp[i][i] = 1;
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (nums1[i] == nums2[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[n - 1][m - 1];
}
};
三、LeetCode 53. 最大子序和
1.题目链接
2.思路
(1)dp[i] 表示[0,i]的最大连续子序和
(2)状态转移
1)dp[i-1]小于0:[0,i-1]最大连续子序和+nums[i] 比nums[i]自身更小
2)dp[i-1]大等于0:dp[i] = dp[i - 1] + nums[i]
(3)初始化
dp[0]=nums[0]
(4)结果:dp[i]的最大值
3.题解
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int dp[n];
dp[0] = nums[0];
int res = dp[0];
for (int i = 1; i < nums.size(); i++) {
if (dp[i - 1] < 0)
dp[i] = nums[i];
else
dp[i] = dp[i - 1] + nums[i];
if (res < dp[i])
res = dp[i];
}
return res;
}
};
四、LeetCode392.判断子序列
1.题目链接
2.思路
(1)dp[i][j] s在[0,i]和t在[0,j]的公共子序列长度
注:这里的公共子序列要求s不能放弃元素,s的元素必须全都加入子序列
(2)转移方程
1)s[i] t[j]相等,则t[j]可以加入子序列 dp[i][j] = dp[i - 1][j - 1] + 1
2)s[i] t[j]不相等,则t[j]不加入子序列,dp[i][j]=dp[i][j-1](只能删除t[j],不能删除s[i])
(3)初始化
只看s[0] 如果有t[j]==s[0] 那么从此以后dp[0][j]均为1
3.题解
class Solution {
public:
bool isSubsequence(string s, string t) {
int n = s.size();
int m = t.size();
if (n == 0)
return true;
if (m == 0)
return false;
vector<vector<int>> dp(n, vector(m, 0));
int flag = 0;
for (int i = 0; i < m; i++) {
if (s[0] == t[i])
flag = 1;
if (flag)
dp[0][i] = 1;
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
if (s[i] == t[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = dp[i][j - 1]; // 因为只能是t删除元素,在算子序列的时候S必须全保留
}
}
return dp[n - 1][m - 1] == s.size();
}
};