动态规划法-LeetCode第53题:最大子序和

动态规划法-LeetCode第53题:最大子序和

前言

……还是一个学生,做题解只是个人记录,代码有不少错误或纰漏之处,还望多多包涵。

题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

分析

该题可用最简单的动态规划法求解。我们可以从输入序列开始位置扫描到结束位置,建立动态规划数组dp,dp[i]表示当以该元素作为结束时,所建立的连续子序列的最大和是多少。对于序列中的每一元素nums[i],对应的dp[i]都有两种取值可能:
1.当上一个动态规划结果dp[i-1]+nums[i]>nums[i]时,表示将该元素纳入前一个元素建立的连续子序列中,得到的和更大。
2.否则,当结果为小于或等于时,证明将该元素定义为起始位置,重新建立子序列得到的连续子序列,肯定大于或等于将其纳入前一序列得到的连续子序列。

简单来说,即dp[i]的取值为max(dp[i-1]+nums[i],nums[i]),亦即纳入前一序列或重新开始新序列。
这样的话就简单了,只要每次扫描都做一次这样的判断,最后从dp中找到最大值,该最大值即代表连续子序列的最大和。
上代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==0)	//考虑序列长度为0
            return 0;
        else if(nums.size() == 1)//考虑序列只有一个元素
            return nums[0];
        else
        {
            vector<int> dp;
            dp.push_back(nums[0]);
            for(int i=1; i<nums.size(); ++i)
            {
                if(nums[i]>dp[i-1]+nums[i])	//重新建立子序列
                    dp.push_back(nums[i]);
                else//纳入前一序列
                    dp.push_back(nums[i]+dp[i-1]);
            }
            int max = dp[0];
            for(int i=1; i<nums.size(); ++i)//找到最大值
                if(dp[i]>max)
                    max=dp[i];
            return max;
        }
    }
};

运行结果:
在这里插入图片描述
顺利通过。

优化

其实我们做了很多不必要的工作,比如我们可以在序列中直接进行修改,而不用建立dp数组。
其次,我们检查到该元素时,即可能为该元素赋新值,因此我们可以同时检查元素当前值是否为序列最大值,避免执行接下来的遍历。
最后,判断条件nums[i]>dp[i-1]+nums[i],可以直接简化成,dp[i-1]<0,当其小于0时,当前元素不应该纳入前一序列,否则肯定会变小。
代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
		if(nums.size()==0)
		    return 0;
		if(nums.size() == 1)
		    return nums[0];
		int max = nums[0];
		for(int i=1; i<nums.size(); ++i)
		{
		    if(nums[i-1]>0)//判断前一元素的最大和是否大于0
		        nums[i]+=nums[i-1];//纳入时直接在原序列修改
		    if(nums[i]>max)	//判断是否为最大和
		        max=nums[i];
		}
		return max;
    }
};

运行结果:
在这里插入图片描述
内存消耗有所优化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值