系列文章目录
前言
每天进步一点点!!
一、背景
给定一个整数数组 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