1. LeetCode 1143.最长公共子序列
题目链接:https://leetcode.cn/problems/longest-common-subsequence/description/
文章链接:https://programmercarl.com/1143.最长公共子序列.html
视频链接:https://www.bilibili.com/video/BV1ye4y1L7CQ
1.确定dp数组(dp table)以及下标的含义
dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
2.确定递推公式
主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同
1️⃣如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
2️⃣如果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]);
3.dp数组如何初始化
统一初始为0。
4.确定遍历顺序
从前向后,从上到下来遍历。
解法:
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
//1.定义dp数组
//dp[i][j]表示以下标i-1结尾的子串a和以下标j-1结尾的子串的最长公共子序列的长度
int[][] dp = new int[text1.length()+1][text2.length()+1];
//2.递推公式
/**
if (text1.charAt(i-1) == text2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1]+1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
*/
//3.初始化
//4.遍历顺序
int res = 0;
for (int i=1;i<text1.length()+1;i++) {
for (int j=1;j<text2.length()+1;j++) {
if (text1.charAt(i-1) == text2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1]+1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
res = Math.max(res,dp[i][j]);
}
}
return res;
}
}
2. LeetCode 1035.不相交的线
题目链接:https://leetcode.cn/problems/uncrossed-lines/description/
文章链接:https://programmercarl.com/1035.不相交的线.html#思路
视频链接:https://www.bilibili.com/video/BV1h84y1x7MP
思路:本题等价于求解公共子序列
解法:
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
//本题等价于求解公共子序列(非连续)
//1.定义dp数组
//dp[i][j]表示以nums[i-1]结尾的序列和以nums2[j-1]结尾的序列的公共子序列长度
int[][] dp = new int[nums1.length+1][nums2.length+1];
//2.递推公式
/**
if (nums1[i-1]==nums2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
*/
//3.初始化
//4.遍历顺序 从前往后
int res=0;
for (int i=1;i<nums1.length+1;i++) {
for (int j=1;j<nums2.length+1;j++) {
if (nums1[i-1]==nums2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
res = Math.max(res,dp[i][j]);
}
}
return res;
}
}
3. LeetCode 53. 最大子序和
题目链接:https://leetcode.cn/problems/maximum-subarray/description/
文章链接:https://programmercarl.com/0053.最大子序和(动态规划).html
视频链接:https://www.bilibili.com/video/BV19V4y1F7b5
思路:
1.确定dp数组(dp table)以及下标的含义
dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]。
2.确定递推公式
dp[i]只有两个方向可以推出来:
nums[i]+dp[i - 1],即:nums[i]加入当前连续子序列和
nums[i],即:从头开始计算当前连续子序列和
一定是取最大的,所以dp[i] = max(nums[i]+dp[i - 1], nums[i]);
3.dp数组如何初始化
dp[0] = nums[0]。
4.确定遍历顺序
递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。
5.返回值
dp数组中的最大值。
解法:
class Solution {
// // 贪心
// public int maxSubArray(int[] nums) {
// int res = nums[0];
// int count = 0;
// for (int i=0;i<nums.length;i++) {
// count += nums[i];
// if (count > res) {// 取区间累计的最大值(相当于不断确定最大子序终止位置)
// res = count;
// }
// if (count <= 0) {
// count = 0;// 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
// }
// }
// return res;
// }
// 动态规划
public int maxSubArray(int[] nums) {
//1.定义dp数组
//dp[i]表示以nums[i]结尾的最大连续子数组之和
int[] dp = new int[nums.length];
//2.递推公式
//dp[i] = Math.max(nums[i]+dp[i-1],nums[i]);
//3.初始化
dp[0]=nums[0];
//4.遍历顺序 从前往后
int res = nums[0];
for (int i=1;i<nums.length;i++) {
dp[i] = Math.max(nums[i]+dp[i-1],nums[i]);
res = Math.max(res,dp[i]);
}
return res;
}
}
4. LeetCode 392.判断子序列
题目链接:https://leetcode.cn/problems/is-subsequence/description/
文章链接:https://programmercarl.com/0392.判断子序列.html
视频链接:https://www.bilibili.com/video/BV1tv4y1B7ym/
思路:与最长公共子序列一致。
解法:
class Solution {
public boolean isSubsequence(String s, String t) {
char[] nums1 = s.toCharArray();
char[] nums2 = t.toCharArray();
//1.定义dp数组
//dp[i][j]表示以nums[i-1]结尾的子序列和以nums[j-1]结尾的子序列的最长公共子序列长度
int[][] dp = new int[nums1.length+1][nums2.length+1];
//2.递推公式
/**
if (nums[i-1]==nums[j-1]) {
dp[i][j] = dp[i-1][j-1]+1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
*/
//3.初始化
//4.遍历顺序
int res = 0;
for (int i=1;i<nums1.length+1;i++) {
for (int j=1;j<nums2.length+1;j++) {
if (nums1[i-1]==nums2[j-1]) {
dp[i][j] = dp[i-1][j-1]+1;
} else {
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
res=Math.max(res,dp[i][j]);
}
}
return res==nums1.length;
}
}