今天晚上的第二弹,动态规划走起!!!
今日任务:
- 1143.最长公共子序列
- 1035.不相交的线
- 53.最大子序和
题目一:1143.最长公共子序列
Leetcode题目:【1143.最长公共子序列】
此问题可以把字符串转为数组,比如:
对于动态规划的问题而言,如何定义两个数组如何去比较,比较状态如何表示和保存。对于这种双数组问题,一般定义一个二维的动态数组,与上面的题目非常相似,还是按照动规五部曲来做:
自己的想法:
(1)定义dp数组: dp[i][j]表示A数组中以i-1为下标,B数组中以j-1为下标的最长公共子序列的长度(为了节省初始化的过程,都初始化为0即可);
(2)递推公式: if(nums1[i-1] == nums2[j-1]) dp[i][j] = dp[i][j-1] + 1;
(3)初始化: 因为i=0那一行没有意义,所以全部初始化为0;j=0那一列也没有意义,所以初始化为0
(4)遍历顺序:从左到右即可;
(5)打印dp数组。
但是这种思路的递推公式是错误的,
当元素的比较值可以分为元素相同和元素不同的情况
如果元素相同,则dp[i][j] = dp[i-1][j-1] + 1;
如果元素不同,则考虑左侧和上面的最大值;
由此可见,就是走一个大的田字格。
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int result = 0;
vector<vector<int>> dp(text1.size()+1, vector<int>(text2.size()+1));
for(int i = 1; i <= text1.size(); i++){
for(int j = 1; j<=text2.size(); 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]);
}
}
}
return dp[text1.size()][text2.size()];
}
};
题目二:1035.不相交的线
Leetcode题目:【1035.不相交的线】
这个题目可以转化为不连续的最大公共子序列,与上一道题目完全一样(相当于套了一个壳子的最长公共子序列),按照田字格的规则和动规五部曲进行分析:
(1)确定dp数组的含义:
下标到i-1的A数组,下标到j-1的B数组中的元素,最长公共子序列的长度;
(2)确定递推公式(田字格规则):
如果两个元素相同,则dp[i][j] = dp[i-1][j-1] + 1;
如果两个元素不同,则dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
(3)初始化:全部都初始化为0;
(4)遍历顺序:根据递推公式,从上到下,从左到右
(5)打印dp数组。
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
vector<vector<int>> dp(nums1.size()+1, vector<int>(nums2.size()+1));
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()];
}
};
题目三:53.最大子序和
Leetcode题目:【53.最大子序和】
自己的思路:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==1) return nums[0];
vector<int> dp(nums.size());
dp[0] = nums[0];
for(int i = 1; i<nums.size(); i++){
dp[i] = max(dp[i], dp[i-1] + nums[i]);
}
return dp[nums.size()-1];
}
};
还是递推方式不正确,根本没有考虑到连续特性。按照动规五部曲:
(1)dp[i]表示以下标i为结尾的,最大连续子序列的和为dp[i];
(2)递推公式:
眼前前面子序列的和,继续累加:dp[i] = dp[i-1] + nums[i];
从自己开始累加:nums[i];
所以:dp[i] = max(nums[i], dp[i-1] + nums[i]);
非常关键的一个点result = num[0];
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==1) return nums[0];
vector<int> dp(nums.size());
dp[0] = nums[0];
int result = nums[0];
for(int i = 1; i<nums.size(); i++){
dp[i] = max(nums[i], dp[i-1] + nums[i]);
if(result < dp[i]) result = dp[i];
}
return result;
}
};