给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。
样例
给出数组 [1, 3, -1, 2, -1, 2]
这两个子数组分别为 [1, 3]
和 [2, -1, 2]
或者 [1, 3, -1, 2]
和 [2]
,它们的最大和都是 7
挑战
要求时间复杂度为 O(n)
注意事项
子数组最少包含一个数
解题思路1:
既然在上一题Lintcode 41:Maximum Subarray已经可以求出整个数组的最大和子数组,那么这个题目就是增加了一条分界线,求分界线左右两边的子数组的最大和相加,很容易想到:遍历分界线,依次求取分界线两端的最大和。这样做的时间复杂度为O(n^2),代码如下:
public class Solution {
/*
* @param nums: A list of integers
* @return: An integer denotes the sum of max two non-overlapping subarrays
*/
public int maxTwoSubArrays(List<Integer> nums) {
// write your code here
int res = Integer.MIN_VALUE;
int[] numss = new int[nums.size()];
for(int i=0; i<nums.size(); i++)
numss[i] = nums.get(i);
for(int i = 1; i < numss.length; i++){
int temp1 = maxSubArray(numss, 0, i-1);
int temp2 = maxSubArray(numss, i, numss.length-1);
res = Math.max(res, temp1+temp2);
}
return res;
}
//求nums[l...r]之间最大子数组和
public int maxSubArray(int[] nums, int l, int r) {
//dp[i]表示以i为结尾子数组的最大和
int[] dp = new int[r-l+1];
dp[0] = nums[l];
int res = nums[l];
for(int i=1; i<r-l+1; i++){
dp[i] = Math.max(dp[i-1]+nums[l+i], nums[l+i]);
res = Math.max(res, dp[i]);
}
return res;
}
}
解题思路2:
同样是上面的思路,但是利用空间换时间的方式,先从左向右遍历,将左边子数组所有最大和保存在一个数组中,再从右向左遍历,将右边子数组所有最大和保存在另一个数组中,最后将两个数组彼此不相交的位置进行相加即可。这样做的时间复杂度为O(n).
class Solution {
public:
/*
* @param nums: A list of integers
* @return: An integer denotes the sum of max two non-overlapping subarrays
*/
int maxTwoSubArrays(vector<int> &nums)
{
// write your code here
vector<int> lRes(nums.size() , INT_MIN);
lRes[0] = nums[0];
int temp = nums[0];
for(int i=1 ; i < nums.size() ; i++)
{
temp = max(temp+nums[i] , nums[i]);
lRes[i] = max(temp , lRes[i-1]);
}
vector<int> rRes(nums.size() , INT_MIN);
rRes[nums.size()-1] = nums[nums.size()-1];
temp = nums[nums.size()-1];
for(int i=nums.size()-2 ; i >=0 ;i--)
{
temp = max(temp+nums[i] , nums[i]);
rRes[i] = max(temp , rRes[i-1]);
}
int res = INT_MIN;
for(int i=0 ; i+1 < nums.size() ; i++)
{
int t = lRes[i] + rRes[i+1];
res = res > t ? res : t;
}
return res;
}
};