文章目录
1.1143最长公共子序列
1.1.题目
; 1.2.解答
本题和动态规划: 718. 最长重复子数组 区别在于这里 不要求是连续的了,但要有相对顺序,即:”ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
继续动规五部曲分析如下:
1.确定dp数组(dp table)以及下标的含义
dp[i][j]
:长度为 [0, i - 1]
的字符串text1与长度为 [0, j - 1]
的字符串text2的最长公共子序列为 dp[i][j]
同理这里的定义和昨天的题目一样,为了方便写递推公式,给dp数组添加了第0行、第0列。
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]);
注意:这里并不是很理解。。。
代码如下:
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]);
}
3.dp数组如何初始化
先看看 dp[i][0]
应该是多少呢?
test1[0, i-1]
和空串的最长公共子序列自然是0,所以 dp[i][0] = 0;
,同理 dp[0][j]
也是0。
其他下标都是随着递推公式逐步覆盖,初始为多少都可以,那么就统一初始为0。
代码:
vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
4.确定遍历顺序
从递推公式,可以看出,有三个方向可以推出 dp[i][j]
,如图。那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵。
5.举例推导dp数组
以输入: text1 = "abcde", text2 = "ace"
为例,dp状态如图
最后给出代码如下,和昨天的题目一样,自己也是做了调整,代码中的
i/j
表示的是 nums
的索引,而不是dp数组的索引。
int longestCommonSubsequence(string text1, string text2)
{
if(text1.empty() || text2.empty())
return 0;
int result = 0;
vector<vector<int>> dp(text1.size()+1, vector<int>(text2.size()+1, 0));
for(int i = 0; i < text1.size(); i++)
{
for(int j = 0; j < text2.size(); j++)
{
if(text1[i] == text2[j])
{
dp[i+1][j+1] = dp[i][j] + 1;
}
else
{
dp[i+1][j+1] = max(dp[i+1][j], dp[i][j+1]);
}
result = dp[i+1][j+1] > result ? dp[i+1][j+1] : result;
}
}
return result;
}
注意:这道题感觉和昨天的题目非常相似,但是当目前的两个数字不相等的时候,为什么是取前面的最长序列的最大值,自己还不是特别明白。。。
2.1035不相交的线
2.1.题目
; 2.2.解答
绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且直线不能相交!
直线不能相交, 这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。
拿示例一A = [1,4,2], B = [1,2,4]为例,相交情况如图:
其实也就是说A和B的最长公共子序列是[1,4],长度为2。 这个公共子序列指的是相对顺序不变(即数字4在字符串A中数字1的后面,那么数字4也应该在字符串B数字1的后面)
这么分析完之后,大家可以发现: 本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!那么本题就和我们刚刚讲过的这道题目 动态规划:1143.最长公共子序列 就是一样一样的了。
这里就不给出代码了,因为和上面的代码其实是完全一样的!
3.53最大子序和
3.1.题目
; 3.2.解答
1.确定dp数组(dp table)以及下标的含义
dp[i]
: 包括下标i之前的 最大连续子序列和为 dp[i]
。注意:这里一定是包含 nums[i]
的,因为是连续的子序列。
2.确定递推公式
dp[i]
只有两个方向可以推出来:
dp[i - 1] + nums[i]
,即:nums[i]
加入当前连续子序列和nums[i]
,即:从头开始计算当前连续子序列和
一定是取最大的,所以 dp[i] = max(dp[i - 1] + nums[i], nums[i]);
注意:以上两种方式,不管那种方式,都一定是包含 nums[i]
的!这个要和dp数组的定义紧密联系到一起!
3.dp数组如何初始化
从递推公式可以看出来 dp[i]
是依赖于 dp[i - 1]
的状态, dp[0]
就是递推公式的基础。根据dp[i]的定义,很明显 dp[0]
应为 nums[0]
,即 dp[0] = nums[0]
。
4.确定遍历顺序
递推公式中 dp[i]
依赖于 dp[i - 1]
的状态,需要从前向后遍历。
5.举例推导dp数组
以示例一为例,输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
,对应的dp状态如下
最后给出代码如下,很简单
int maxSubArray(vector<int> &nums)
{
if(nums.empty())
return 0;
vector<int> dp(nums.size(), 0);
dp[0] = nums[0];
int result = dp[0];
for(int i = 1; i < nums.size(); i++)
{
dp[i] = max(nums[i], dp[i-1] + nums[i]);
result = dp[i] > result ? dp[i] : result;
}
return result;
}
Original: https://blog.csdn.net/qq_42731705/article/details/127818958
Author: Cc1924
Title: 代码随想录53——动态规划:1143最长公共子序列、1035不相交的线、53最大子序和
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/657495/
转载文章受原作者版权保护。转载请注明原作者出处!