剑指offer. 42 连续子数组的最大和(重要)
题目描述:
输入一个整形数组,数组里有正数和负数。数组中的一个或连续多个整数数组做成一个子数组。 求所有子数组的和的最大值。要求时间复杂度为O(n),如:{1,-2,3,10,-4,7,2,-5}, 和最大的子数组是{3,10,-4,7,2},所以输出和 18
解题思路:
解法1: 动态规划
这种找子数组最优,一般解法是依次求以x【i】为结尾的最优解,并且利用到上一个的解
F(i):以array[i]为末尾元素的子数组的和的最大值
递推公式:F(i)=max(F(i-1)+array[i] , array[i])初始状态 F(0) = array[0];
res:所有子数组的和的最大值
res=max(res,F(i))如数组[6, -3, -2, 7, -15, 1, 2, 2]
初始状态:
F(0)=6
res=6
i=1:
F(1)=max(F(0)-3,-3)=max(6-3,3)=3
res=max(F(1),res)=max(3,6)=6
i=2:
F(2)=max(F(1)-2,-2)=max(3-2,-2)=1
res=max(F(2),res)=max(1,6)=6
i=3:
F(3)=max(F(2)+7,7)=max(1+7,7)=8
res=max(F(2),res)=max(8,6)=8
i=4:
F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7
res=max(F(4),res)=max(-7,8)=8
以此类推
最终res的值为8
动规代码:
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
if(array.empty()) return 0;
int res = array[0];// 最终结果 注意初始值 不能设为0 防止只有负数
int dp= array[0]; //以array[i]为末尾元素的子数组的和的最大值
for(int i = 1; i < array.size(); i++) //从1开始 因为0的情况在初始化时完成了
{
dp = max(dp+array[i],array[i]);
res = max(dp,res);
}
return res;
}
};
解法2代码:
(不看这种解法)
我也不知道怎么形容这个解法,简单说维持一个cur变量,然后遍历数组,假如cur+arr【i】>=0 就表示还有救,如果小于0了,就表示没救了。
因为假如[a..b..c] 这一部分sum<0 ,则这一块的任何一个子集都不可能是结果的一部分。 【a。。。b】不可能是结果的一部分是显然的,但【b。。c】为什么也不可能呢?因为a到c小于0,而a到b因为没有gg,所以大于0,所以b到c肯定也小于0,所以不可能。总的来说 cur累加成为负数就清0,重新累加,res记录cur的最大值。
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
if(array.empty()){
return 0;
}
int res= INT_MIN;
int cur=0;
int len = array.size();
for(int i=0;i!=len;++i){
cur += array[i];
/*
if(cur<0) cur=0;
else res = max(res,cur);
之前的代码 没有考虑全负的情况!!
*/
res = max(res,cur);
cur = cur<0?0:cur;
}
return res;
}
};