怎么使用动态规划——最大子序和(leetcodeT53)

怎么样才能较快的用出动态规划,做了力扣的每日一题,复习一遍动态规划。
任何情况下,暴力法都是最简单和最直接的思路。任何解题技巧或优化,都是在暴力的基础上进行优化。所以,如果不是很熟悉优化解法,不要一开始就直接想动态规划怎么做这个题。先用暴力想出来问题,然后优化时间空间。
从下面这个题来解释。

题目:
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
思路:
暴力:
既然要最大和的连续子序列,那么暴力解法就是找出所有的子序列,然后比较出最大的和。我们从1组合到最后,算出和,用一个max来存储最大值,然后从2往后挨个组合……很简单,只是时间复杂度就比较高了最外层是从1-n,然后里面嵌套了n-1~1.平均lgn。所以时间复杂度是O(nlgn)。空间复杂度,我们需要一个sum来存和,需要一个max来存最大值,所以空间复杂度O(1)。
代码就不写了,很简单。现在我们开始优化。我们都做过加法,如果要让和变大,那么我们要加的应该是大于0的数。所以,和小于0的子序列是需要剔除出去的,也就是暴力中可以删去这部分。再有,我们需要的是连续子数组。那么,当前面的和小于0的时候,就可以把这部分也从暴力中剔除出去。
所以动态规划的思路就出来了。我在从1开始遍历,记录sum,当sum小于0的时候,以此位置为头,重新计算sum。
代码来讲:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int len=nums.size();
        int back=0;//记录当前位置
        int max=nums[0];//记录最大值,以首位置当第一位
        int sum=0;//sum记录子序列和
        while(back<len)
        {
            sum+=nums[back];//动态计算序列和
            if(sum>max)//如果大于max,就记录下来
            {
                max=sum;
            }
            if(sum<=0)//如果前面的序列和小于0,则剔除这段序列,重新开始计算sum
            {
                sum=0;
            }
            back++;//后移一位
        }
        return max;
    }
};

这是最简单的优化思路,动态规划。我的思想是直接看sum来剔除。还有另外一种思路是有点像背包问题里的,我判断加上这个数之后比它本身大还是小(其实就是加了个小于0的数嘛)。代码会比较精简易读。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int len=nums.size();
        int pre=0;//上一段代码里的sum
        int maxs=nums[0];
        for(auto a:nums)//auto在for里就是这么神奇
        {
            pre=max(pre+a,a);//看上一个序列是否大于0,是则pre+a,否则更新为a
            maxs=max(maxs,pre);//更新max
        }
        return maxs;
    }
};

其实,动归并没有很可怕,讲暴力中不必要的部分剔除出去,剔除的方法其实可以看作是if,然后用一个动态变化的记录,来使得一次遍历考虑到所有情况的效果。
over,温故而知新。加油。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值