【Day57】代码随想录之动态规划part14——最长公共子序列、不相交的线、最大子序列和

本文介绍了如何使用动态规划解决LeetCode中的三个问题:最长公共子序列(1143、1035),不相交线问题(1035),以及最大子序和(53)。作者详细解释了如何定义和填充动态规划数组,以及正确应用递推公式和边界条件。
摘要由CSDN通过智能技术生成

今天晚上的第二弹,动态规划走起!!!

今日任务:

  • 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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值