要思考dp是由哪几个状态推导而来
1143.最长公共子序列
文章链接:代码随想录 (programmercarl.com)
思路:无思路
看完文章后的反思:与718.最长重复子数组的区别在于,此题不要求是连续的
(1)确定dp数组含义
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]不相同
如果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]);
(3)初始化
初始化为0
(4)确定遍历顺序
根据递推公式,可以发现应当从前往后,从上到下
(5)举例推导验证
Java代码:(思路如上)
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
//先判断特殊情况
if(text1.length() == 0 || text2.length() == 0){
return 0;
}
int len1 = text1.length();
int len2 = text2.length();
//确定dp数组
//dp数组表示长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
int[][] dp = new int[len1 + 1][len2 + 1];
//初始化,数组初始化默认全为0
//确定遍历顺序和递推公式
for(int i = 1; i <= len1;i++){
char c1 = text1.charAt(i - 1);
for(int j = 1;j <= len2;j++){
char c2 = text2.charAt(j - 1);
if(c1 == c2){
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else{
dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1]);
}
}
}
return dp[len1][len2];
}
}
1035.不相交的线
文章链接:代码随想录 (programmercarl.com)
思路:本题与1143.最长公共子序列思路一模一样,遵循动规五步曲
(1)确定dp数组及其含义
dp[i][j]表示长度为[0, i - 1]的数组nums1与长度为[0, j - 1]的数组nums2的最长公共子序列为dp[i][j]
(2)确定递推公式
跟1143题一样,如果nums1[i - 1] 与 nums2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
如果nums1[i - 1] 与 nums2[j - 1]不相同,dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
(3)初始化
初始化为0
(4)确定遍历顺序
从前向后,从上到下
(5)举例推导验证
Java代码:(思路如上)
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
//先判断特殊情况
if(nums1.length == 0 || nums2.length == 0){
return 0;
}
int len1 = nums1.length;
int len2 = nums2.length;
//确定dp数组
int[][] dp = new int[len1 + 1][len2 + 1];
//初始化,数组初始化默认全为0
//确定遍历顺序和递推公式
for(int i = 1; i <= len1;i++){
for(int j = 1;j <= len2;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]);
}
}
}
return dp[len1][len2];
}
}
53. 最大子序和
文章链接:代码随想录 (programmercarl.com)
思路:之前用的是贪心算法做的,这次用动态规划的思路
(1)确定dp数组以及含义
dp[i] 表示在区间[0,i - 1]中的最大和为dp[i]
(2)确定递推公式(自己在考虑递推公式时少考虑了一种情况)
a. dp[i] = dp[i - 1] + nums[i];
b. dp[i] = nums[i];(从当前开始另外计算)
因此 dp[i] = Math.max(dp[i - 1] + nums[i],nums[i]);
(3)初始化
dp[0] = nums[0],其余为0;
(4)确定遍历顺序
从前往后
(5)举例推导验证
实现代码遇到的问题:
(1)确定递推公式(自己在考虑递推公式时少考虑了一种情况)
(2)定义res时,初始化了为0,错误,如果整个数组全为负数,那么就不可能返回0,因此应该定义 int res = nums[0]
Java代码:
class Solution {
public int maxSubArray(int[] nums) {
//先判断特殊情况
if(nums.length == 0 || nums == null){
return 0;
}
if(nums.length == 1){
return nums[0];
}
int len = nums.length;
//确定dp数组
int[] dp = new int[len];
//初始化
dp[0] = nums[0];
int res = nums[0];
//确定遍历顺序以及递推公式
for(int i = 1; i < len;i++){
dp[i] = Math.max(dp[i - 1] + nums[i],nums[i]);
if(dp[i] > res){
res = dp[i];
}
}
return res;
}
}