Description
In a given array nums
of positive integers, find three non-overlapping subarrays with maximum sum.
Each subarray will be of size k
, and we want to maximize the sum of all 3*k
entries.
Return the result as a list of indices representing the starting position of each interval (0-indexed). If there are multiple answers, return the lexicographically smallest one.
Example:
Input: [1,2,1,2,6,7,5,1], 2
Output: [0, 3, 5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.
Note:
-
nums.length
will be between 1 and 20000.*nums[i]
will be between 1 and 65535.*k
will be between 1 and floor(nums.length / 3).
Solution
DFS (TLE)
DP
The question asks for three non-overlapping intervals with maximum sum of all 3 intervals. If the middle interval is [i, i+k-1], where k <= i <= n-2k, the left interval has to be in subrange [0, i-1], and the right interval is from subrange [i+k, n-1].
So the following solution is based on DP.
- posLeft[i] is the starting index for the left interval in range [0, i];
- posRight[i] is the starting index for the right interval in range [i, n-1];
Then we test every possible starting index of middle interval, i.e. k <= i <= n-2k, and we can get the corresponding left and right max sum intervals easily from DP. And the run time is O(n).
Caution. In order to get lexicographical smallest order, when there are two intervals with equal max sum, always select the left most one. So in the code, the if condition is ">= tot" for right interval due to backward searching, and "> tot" for left interval.
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int n = nums.length;
int[] sum = new int[n + 1];
for (int i = 0; i < n; ++i) {
sum[i + 1] = nums[i] + sum[i];
}
// leftPos[i] = j means [j, j + k) is the max of [0, i]
int[] leftPos = new int[n];
for (int i = k, tot = getKSum(sum, 0, k); i < n; ++i) {
if (getKSum(sum, i - k + 1, k) > tot) {
leftPos[i] = i - k + 1;
tot = getKSum(sum, i - k + 1, k);
} else {
leftPos[i] = leftPos[i - 1];
}
}
int[] rightPos = new int[n];
rightPos[n - k] = n - k;
for (int i = n - k - 1, tot = getKSum(sum, n - k, k); i >= 0; --i) {
if (getKSum(sum, i, k) >= tot) {
rightPos[i] = i;
tot = getKSum(sum, i, k);
} else {
rightPos[i] = rightPos[i + 1];
}
}
int[] res = new int[3];
int maxSum = 0;
for (int i = k; i <= n - 2 * k; ++i) {
int curr = getKSum(sum, i, k)
+ getKSum(sum, leftPos[i - 1], k)
+ getKSum(sum, rightPos[i + k], k);
if (curr > maxSum) {
maxSum = curr;
res[0] = leftPos[i - 1];
res[1] = i;
res[2] = rightPos[i + k];
}
}
return res;
}
public int getKSum(int[] sum, int start, int k) {
return sum[start + k] - sum[start];
}
}