描述
给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。
子数组最少包含一个数
样例
给出数组 [1, 3, -1, 2, -1, 2]
这两个子数组分别为 [1, 3] 和 [2, -1, 2] 或者 [1, 3, -1, 2] 和 [2],它们的最大和都是 7
挑战
给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。
子数组最少包含一个数
样例
给出数组 [1, 3, -1, 2, -1, 2]
这两个子数组分别为 [1, 3] 和 [2, -1, 2] 或者 [1, 3, -1, 2] 和 [2],它们的最大和都是 7
挑战
要求时间复杂度为 O(n)
分析
最开始,我打算将该问题转化为求最小连续子数组之和问题,然后用原始数组之和减去最小连续子数组之和,但是发现在很多特例的时候不好使。最后不得不从正向思路出发,对该问题转化为求两个最大连续子数组的问题。
将数组从左向右扫一次,初始化当前最大值结果maxvalue,每次相加之和的结果sum,存放每次操作之和的maxvalue值得数组left。遍历数组,判断sum是否大于0,如果大于零,则sum加上当前数组的值;否则说明这之前没有连续最大子数组,sum等于当前数组的值,从新开始计算。
在每次相加或者赋值sum之后,判断sum和maxvalue的大小,如果sum大,则maxvalue=sum,否则保持maxvalue值不变,用left存下每遍历一个数组之和的maxvalue结果。
然后将数组从右向左扫一次,同样的操作,将maxvalue在每遍历一个数之后放入right数组中。
最后,遍历left,right数组,left[i]+right[i+1]表示在第i位拆分数组,得到其子数组的和。
程序
class Solution {
public:
/*
* @param nums: A list of integers
* @return: An integer denotes the sum of max two non-overlapping subarrays
*/
/*
从左自右、从右自左分别遍历数组。每次遍历均记录当前最大的单子数组,
用2个数组left,right保存。如left[i]的值表示nums从0至i中最大子数组的值,
right[i]的值表示nums从i至size-1中最大子数组的值。
最后遍历left,right数组,left[i]+right[i+1]
表示在第i位拆分数组,得到其子数组的和。
*/
int maxTwoSubArrays(vector<int> &nums) {
// write your code here
int size = nums.size();
int sum,maxvalue;
int *left = new int[size];
left[0] = sum = maxvalue =nums[0];
for(int i = 1; i < size; i++){
if(sum > 0)
sum += nums[i];
else
sum = nums[i];
if(sum > maxvalue)
maxvalue = sum;
left[i] = maxvalue;
}
int *right = new int[size];
right[size-1] = sum = maxvalue = nums[size-1];
for(int i = size-2; i >= 0; i--){
if(sum > 0)
sum += nums[i];
else
sum = nums[i];
if(sum > maxvalue)
maxvalue = sum;
right[i] = maxvalue;
}
int result = 0x80000000;
for(int i = 0; i < size-1; i++){
result = (result > (left[i]+right[i+1]) ? result : (left[i]+right[i+1]));
}
return result;
}
};