leetcode - 53. 最大子序和 152. 乘积最大子序列 - 两个算法之间的联系和区别

这两道算法题的解题思路是差不多的,但是从整体上分析,乘积最大子序列之和是最大子序和的进阶。先来看看两道算法题的简单描述。

53.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
在这里插入图片描述
简单分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
——————————————————————————————————————————
53.最大子序和的代码:
个人觉得,在动态规划问题中,定义好状态和状态转移方程是最难了。找到了合适的状态转移方程,写代码就比较简单了。对于该题,最巧妙的就是dp[i]表示的是以nums[i]结尾的最大连续子数组之和,而不是表示nums[0]到nums[i]的最大子序列之和。后者设定的状态很难找到状态转移方程,而前者的状态可以很轻松找到状态转移方程。具体的C++代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int length = nums.size();
        vector<int> dp(length,0);
        dp[0] = nums[0];
        int num = dp[0];
        for(int i=1;i<length;i++)
        {
            if(dp[i-1]>=0) //如果dp[i-1]大于零,则无论当前nums[i]的值大于零还是小于零,都可以直接加上,因为一个数加上一个正数,肯定是大于这个数的
                dp[i] = dp[i-1] + nums[i];
            else
                dp[i] = nums[i];  //如果dp[i-1]小于零,则另起炉灶,因为一个数加上一个负数,无论如何都是小于这个数的
            num = max(num,dp[i]);
        }
        return num;
    }
};

——————————————————————————————————————————
152. 乘积最大子序列
给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
在这里插入图片描述
解题思路
这道题的解题方法和前面那道题是一样的。但是为什么是进阶呢?进阶的地方就在于不是加法而是乘法。考虑一下,在加法中,一个数(不管是正负),加上一个正数,其值必定比原来大。当加上一个负数时,其值必定比原来的小。

但是在乘法运算中,一个正数,乘于一个正数(正整数,大于等于)时,其值至少大于等于原来的值。一个负数,乘于一个正数时,其值却比原来的更小,这个地方,就是乘法和加法的区别。在加法中,一个负数加上一个正数,其值必定大于原来的值。同理,一个负数乘于一个负数,最后的结果是一个正数,这也是和加法是有区别的。这就是需要考虑的地方,需要分类讨论。当nums[i]的值和dp[i-1]的值的正负关系不同的时候,状态转移方程怎么写。

其C++代码如下:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int length = nums.size();
        vector<int> maxl(length,0); //用于存储nums[i]结尾的当前最大值
        vector<int> minl(length,0); //用于存储nums[i]结尾的当前最小值
        maxl[0] = nums[0]; //初始化为nums[0];
        minl[0] = nums[0]; //初始化为nums[0];
        int num = nums[0]; //最后返回的乘积最大子序列的值
        for(int i=1;i<length;i++)
        {
            if(nums[i]>0)  //当nums[i]大于零时,不论前面的dp[i-1]大于零还是小于零,大于零的必定更大,小于零的必定更小
            {
                maxl[i] = max(nums[i],nums[i]*maxl[i-1]);
                minl[i] = min(nums[i],nums[i]*minl[i-1]);
            }
            else if(nums[i]<0)  //当nums[i]小于零时,dp[i-1]小于零时变为大于零,dp[i-1]大于零时变为小于零
            {
                maxl[i] = max(nums[i],nums[i]*minl[i-1]);
                minl[i] = min(nums[i],nums[i]*maxl[i-1]);
            }
            else  //当nums[i]的值为零时,最大和最小值都是0
            {
                manl[i] = 0;
                minl[i] = 0;
            }
            num = max(num,maxl[i]);  //存储当前的最大序列乘积值
        }
        return num;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值