1.题目
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.题解
贪心
先将数组第一个元素存到返回值中,防止只有一个元素并且为负数时错误;
思路是:维护sum变量,记录前几项的和,每次更新res记录最大和,若为sum正数继续加,若为负数,则应该将sum变量置为使得sum为负数的下一个元素值。最终返回res。
class Solution
{
public:
int maxSubArray(vector<int>& nums)
{
int res = nums[0], sum = 0;
for(int num : nums)
{
if(sum >= 0) sum += num;
else sum = num;
res = max(res, sum);
}
return res;
}
};
动态规划
再一次遍历中,更新以第i位结尾时,用一个数组记录子序列和的最大值,之后线性查找最大值即可。
空间优化,数组可以用一个在循环外面的变量记录以当前项结尾的最大值。
class Solution
{
public:
int maxSubArray(vector<int>& nums)
{
int res = nums[0], sum = 0; //res记录结果,sum记录当前以i结尾的最大和
for(int num : nums)
{
sum = max(num, sum + num); //比较第i项 和第i项加前i-1项的和中的较大者
res = max(res, sum); //记录前i项中最大的子序列和
}
return res;
}
};
分治
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;
}
};