Question
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.
Note 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 sum 7.
Analysis
This is not an easy question. I thought I have to use DP 2 times:
- first time, calculate max sum ending at each point.
- second time, calculate max sum to the left/right of a point (inclusive but not necessarily ending at current point).
After a second thought, the first DP path can be denoted with a single variable. So there comes the solution below.
Code
public int maxTwoSubArrays(ArrayList<Integer> nums) {
// write your code
int len = nums.size();
int[] dp1 = new int[len];
int[] dp2 = new int[len];
// dp1[k] denotes the max sum to the left of k (inclusive)
// dp2[k] denotes the max sum to the right of k (inclusive)
dp1[0] = nums.get(0);
int sumSoFar = Math.max(0, nums.get(0));
for (int i = 1; i < len; i++) {
sumSoFar += nums.get(i);
dp1[i] = Math.max(dp1[i - 1], sumSoFar);
sumSoFar = Math.max(0, sumSoFar);
}
dp2[len - 1] = nums.get(len - 1);
sumSoFar = Math.max(0, nums.get(len - 1));
for (int i = len - 2; i >= 0; i--) {
sumSoFar += nums.get(i);
dp2[i] = Math.max(dp2[i + 1], sumSoFar);
sumSoFar = Math.max(0, sumSoFar);
}
// now for every node, calculate leftMaxSum + rightMaxSum
int maxSum = Integer.MIN_VALUE;
for (int i = 0; i < len - 1; i++) {
maxSum = Math.max(maxSum, dp1[i] + dp2[i + 1]);
}
return maxSum;
}