一、题目
https://leetcode.cn/problems/maximum-subarray/submissions/568155647/
二、思路&代码
V1.0:
一般看到连续子序列或子数组优先考虑的都是前缀和数组,但是在本题中我们可以采用两个变量来判断。①cursum,用来记录连续子数组截止到目前的和,②maxres,用来记录连续子数组的最大和。关键点:当cursum<0时,我们就把cursum置为0,从头开始计算,因为一旦前面那一串小于0了,后面的再加上前面那一串势必是减小的,所以不可能成为最大连续子数组,故我们从头开始构造,代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len=nums.size();
int cursum=0;
int maxres=0;
//如果<0,则说明加上前面那一串肯定不会更大
for(int i=0;i<len;i++)
{
cursum+=nums[i];
maxres=max(maxres,cursum);
if(cursum<0) cursum=0;
}
return maxres;
}
};
但是这个版本在提交的时候部分点wa了,经过观察发现这个版本没有考虑到最大子数组和始终是负数的情况,这种情况下上述代码仍然返回0,显然是不对的,所以我们进行下面改进:
V2.0:
class Solution {
public:
//1.0:没有考虑到全是负数的情况,或者任一子数组和都是负数的情况
int maxSubArray(vector<int>& nums) {
int len=nums.size();
int cursum=0;
int maxres=0;
//如果<0,则说明加上前面那一串肯定不会更大
for(int i=0;i<len;i++)
{
cursum+=nums[i];
//以免0永远为最小值
if(i>0) maxres=max(maxres,cursum);
else maxres=cursum;
//cursum+=nums[i];
if(cursum<0) cursum=0;
}
return maxres;
}
};
在这段代码中,我们新增了一个判断条件,即在开始的初始化时,我们让maxres的值直接等于第一个元素的值,而不是0,这样就能保证以免0永远是最小值的问题,实际上,可以直接简化为下面版本,代码如下:
V3.0:
class Solution {
public:
//1.0:没有考虑到全是负数的情况,或者任一子数组和都是负数的情况
int maxSubArray(vector<int>& nums) {
int len=nums.size();
int cursum=0;
int maxres=nums[0];
//如果<0,则说明加上前面那一串肯定不会更大
for(int i=0;i<len;i++)
{
cursum+=nums[i];
maxres=max(maxres,cursum);
if(cursum<0) cursum=0;
}
return maxres;
}
};
V4.0:
以上算法的时间复杂度均为O(n),本题还可以考虑用分治法来做,即它的最大子数组和要么在左半边,要么在右半边,要么是穿过中间,对于左右边的序列,情况也是一样的。分别计算后返回左、右、中三者的最大值即可,用递归不断将大问题化解成小问题,然后分解实现。这时的事件复杂度是O(nlogn),可以自行尝试代码,最后也能通过