Given an array of integers, find two non-overlapping subarrays which have the largest sum.
The number in each subarray should be contiguous.
Return the largest sum.
The subarray should contain at least one number
Example
For given[1, 3, -1, 2, -1, 2], the two subarrays are[1, 3]and[2, -1, 2]or[1, 3, -1, 2]and[2], they both have the largest sum7.
Challenge
Can you do it in time complexity O(n) ?
Analysis
Maximum Subarray II 与 Maximum Subarray I 相比,有几处难点:
用 local 变量更新然后返回 global 最优还不够,需要保存对于每一个子问题的 global 最优(可能并不以当前位置结尾),用于后面的左右两边全局查询
相比 Prefix Sum,个人更偏好Kadane's Algorithm,但是用 Kadane's Algorithm 要注意初始化问题(从头到尾循环,必须要以 nums[0] 做初始化,从 index = 1 开始搜;或者从尾到头循环则以nums[n-1]初始化,从index = n - 2开始)。
Solution
Kadane's Algorithm - O(n) space, O(n) time
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) {
if (nums == null || nums.size() == 0) return 0;
int n = nums.size();
// left[] stores the global max subarray sum for [0, ..., i]
int[] left = new int[n];
// right[] stores the global max subarray sum for [i, ..., n - 1]
int[] right = new int[n];
// Initialize left[] array
left[0] = nums.get(0);
int prevMax = left[0];
int max = left[0];
// Loop from left to right
for (int i = 1; i < n; i++) {
prevMax = Math.max(prevMax + nums.get(i), nums.get(i));
max = Math.max(max, prevMax);
left[i] = max;
}
// Initialize right[] array
right[n - 1] = nums.get(n - 1);
prevMax = right[n - 1];
max = right[n - 1];
// Loop from right to left
for (int i = n - 2; i >= 0; i--) {
prevMax = Math.max(prevMax + nums.get(i), nums.get(i));
max = Math.max(max, prevMax);
right[i] = max;
}
// Find max sum of left and right subarrays
int result = Integer.MIN_VALUE;
for (int i = 0; i < n - 1; i++) {
result = Math.max(result, left[i] + right[i + 1]);
}
return result;
}
}
Prefix Sum Approach - O(n) space, O(n) time
public class Solution {
/**
* @param nums: A list of integers
* @return: An integer denotes the sum of max two non-overlapping subarrays
*/
public int maxTwoSubArrays(ArrayList<Integer> nums) {
// write your code
if(nums == null || nums.size() == 0) return 0;
int n = nums.size();
// Maximum subarray value from left/right with n elements
int[] left = new int[n];
int[] right = new int[n];
int prefixSum = 0;
int minSum = 0;
int max = Integer.MIN_VALUE;
for(int i = 0; i < n; i++){
prefixSum += nums.get(i);
max = Math.max(max, prefixSum - minSum);
minSum = Math.min(minSum, prefixSum);
left[i] = max;
}
prefixSum = 0;
minSum = 0;
max = Integer.MIN_VALUE;
for(int i = n - 1; i >= 0; i--){
prefixSum += nums.get(i);
max = Math.max(max, prefixSum - minSum);
minSum = Math.min(minSum, prefixSum);
right[i] = max;
}
int rst = Integer.MIN_VALUE;
for(int i = 0; i < n - 1; i++){
rst = Math.max(rst, left[i] + right[i + 1]);
}
return rst;
}
}