Given an array of integers nums
and two integers firstLen
and secondLen
, your task is to find two non-overlapping subarrays of lengths firstLen
and secondLen
such that the sum of their elements is maximized. The subarrays must not overlap, meaning no index is used in both subarrays. Return the maximum possible sum of these two subarrays.
firstLen
and secondLen
respectively.nums
are integers, and you must not reuse any element in both subarrays.At first glance, this problem looks similar to finding the maximum sum subarray, but with the added twist of needing two subarrays of specific lengths that do not overlap. A brute-force approach would be to try every possible pair of non-overlapping subarrays, but this would be too slow for large arrays.
To optimize, we need to efficiently compute the maximum sum of subarrays of fixed lengths as we traverse the array. By using prefix sums, we can quickly calculate the sum of any subarray. The key insight is to, for each possible split, keep track of the best subarray sum seen so far for one length, and combine it with the current subarray sum of the other length, considering both possible orders (firstLen before secondLen and vice versa).
This approach leverages dynamic programming principles and sliding window techniques to avoid redundant calculations and ensure we never pick overlapping subarrays.
firstLen
and secondLen
as we iterate.
firstLen
seen so far, and then for each possible position of the secondLen
subarray (after the first), calculate their sum. Do the same with the order reversed.
This approach ensures we always respect the non-overlapping constraint and efficiently finds the optimal solution.
Suppose nums = [0,6,5,2,2,5,1,9,4]
, firstLen = 1
, secondLen = 2
.
This process ensures we consider all valid, non-overlapping pairs and always find the maximum.
This optimization is possible due to the use of prefix sums and sliding windows, avoiding redundant calculations.
The key to solving the Maximum Sum of Two Non-Overlapping Subarrays problem efficiently is to combine prefix sums with sliding window techniques. By considering both possible orders of the subarrays and always tracking the best subarray sum so far, we can guarantee the optimal solution in linear time. This method elegantly avoids overlap and leverages dynamic programming principles, making it both efficient and easy to understand.
def maxSumTwoNoOverlap(nums, firstLen, secondLen):
def maxSum(L, M):
n = len(nums)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i+1] = prefix[i] + nums[i]
maxL = res = 0
for i in range(L + M, n + 1):
maxL = max(maxL, prefix[i - M] - prefix[i - M - L])
res = max(res, maxL + prefix[i] - prefix[i - M])
return res
return max(maxSum(firstLen, secondLen), maxSum(secondLen, firstLen))
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& nums, int firstLen, int secondLen) {
return max(helper(nums, firstLen, secondLen), helper(nums, secondLen, firstLen));
}
int helper(vector<int>& nums, int L, int M) {
int n = nums.size();
vector<int> prefix(n + 1, 0);
for (int i = 0; i < n; ++i) {
prefix[i + 1] = prefix[i] + nums[i];
}
int maxL = 0, res = 0;
for (int i = L + M; i <= n; ++i) {
maxL = max(maxL, prefix[i - M] - prefix[i - M - L]);
res = max(res, maxL + prefix[i] - prefix[i - M]);
}
return res;
}
};
class Solution {
public int maxSumTwoNoOverlap(int[] nums, int firstLen, int secondLen) {
return Math.max(maxSum(nums, firstLen, secondLen), maxSum(nums, secondLen, firstLen));
}
private int maxSum(int[] nums, int L, int M) {
int n = nums.length;
int[] prefix = new int[n + 1];
for (int i = 0; i < n; ++i) {
prefix[i + 1] = prefix[i] + nums[i];
}
int maxL = 0, res = 0;
for (int i = L + M; i <= n; ++i) {
maxL = Math.max(maxL, prefix[i - M] - prefix[i - M - L]);
res = Math.max(res, maxL + prefix[i] - prefix[i - M]);
}
return res;
}
}
var maxSumTwoNoOverlap = function(nums, firstLen, secondLen) {
function maxSum(L, M) {
const n = nums.length;
const prefix = new Array(n + 1).fill(0);
for (let i = 0; i < n; ++i) {
prefix[i + 1] = prefix[i] + nums[i];
}
let maxL = 0, res = 0;
for (let i = L + M; i <= n; ++i) {
maxL = Math.max(maxL, prefix[i - M] - prefix[i - M - L]);
res = Math.max(res, maxL + prefix[i] - prefix[i - M]);
}
return res;
}
return Math.max(maxSum(firstLen, secondLen), maxSum(secondLen, firstLen));
};