09 力扣热题刷题记录之第53题最大子序和

系列文章目录

力扣刷题记录


前言

每天进步一点点!!

一、背景

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

示例 1:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray

二、我的思路

动态规划。

使用一个数组记录,如dp[i]记录为,以下标 i 结尾所能连续的最大长度和是为多少。因而,只需把每次的dp[i]记录即可。

当记录dp[i+1]时,无需再重复计算前面的,只需考虑,当前的值与dp[i]+当前的值谁大即可,与此同时记录最大的值是什么。

代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==1) return nums[0];

        vector<int> dp;//记录子数组的最大长度和
        //在没有初始化之前,不能用下标访问,只能用push——back
        dp.push_back ( nums[0] );
        int maxSum=dp[0];
        for(int i=1;i<nums.size();i++)
        {

            int u=(dp[i-1]+nums[i]) > nums[i]? dp[i-1]+nums[i] : nums[i] ;
            dp.push_back(u);

            maxSum=max(maxSum,u);       
        }
        return maxSum;
    }
};

如果题目要求返回连续的数组,这个时候只需记录最大和的那个下标,以及长度信息。就是每次比较
(dp[i-1]+nums[i]) > nums[i]? dp[i-1]+nums[i] : nums[i]
时,同时记录长度信息。

三、官方的思路

它给了两个思路,第一个思路与我是一致的。这里主要将第二个思路。

采用分治法。即在中间把这个数组切一刀,同时计算左右子区间的几个信息值:

对于一个区间 [l,r] ,我们可以维护四个量:

lSum 表示 [l,r] 内以 l 为左端点的最大子段和
rSum 表示 [l,r]内以 r 为右端点的最大子段和
mSum 表示 [l,r]内的最大子段和
iSum 表示 [l,r] 的区间和

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
来源:力扣(LeetCode)

至于为什么是这四个信息量,大概是因为这四个信息量可以得出我们想要求得内容。

来,既然刚刚把一个数组划分为了两部分,这个时候考虑两个问题:

1、递归的出口?

其实就是当子区间内只有一个元素的时候,就开始往回退了。

2、区间如何合并?

当有了四个维护的量,我们来看一下,一个完整区间的这四个量该怎么求?

isum 最简单,左右两边加起来即可。
lsum,左侧字符开始的最大长度,要么是左子区间的lsum,要么是跨过了中点,左子区间isum加上右子区间的rsum。
rsum呢。要么就是rsum,要么从中点前开始计算,即左子区间的rsum加上右子区间的isum
msum.区间内最大和,这个简单,
在这里插入图片描述

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
来源:力扣(LeetCode)

具体代码如下:

class Solution {
public:
    struct Status {
        int lSum, rSum, mSum, iSum;
    };

    Status pushUp(Status l, Status r) {
        int iSum = l.iSum + r.iSum;
        int lSum = max(l.lSum, l.iSum + r.lSum);
        int rSum = max(r.rSum, r.iSum + l.rSum);
        int mSum = max(max(l.mSum, r.mSum), l.rSum + r.lSum);
        return (Status) {lSum, rSum, mSum, iSum};
    };

    Status get(vector<int> &a, int l, int r) {
        if (l == r) {
            return (Status) {a[l], a[l], a[l], a[l]};
        }
        int m = (l + r) >> 1;
        Status lSub = get(a, l, m);
        Status rSub = get(a, m + 1, r);
        return pushUp(lSub, rSub);
    }

    int maxSubArray(vector<int>& nums) {
        return get(nums, 0, nums.size() - 1).mSum;
    }
};

使用分治法的好处在这里:
在这里插入图片描述

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
来源:力扣(LeetCode)

总结

其实分治法本质上是通过递归完成的。递归最主要的就是两,一个是递归公式,第二个是递归出口。

理解官方思路,第一个明白怎么分治的,第二个明白,如果取得我们需要用来结题的信息。就是上面描述的那四个维护的变量。

还是有点难想的。

喜欢就点个赞叭!!1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值