链接:https://leetcode.com/problems/maximum-sum-of-two-non-overlapping-subarrays/
思路
Approach 1: 假设L子串在M子串左边。反向迭代A,到达位置i时,计算M子串[i, i+M)总和,并记录到i时已计算的M子串总和的最大值maxMSum[i]。然后正向迭代A,到达位置i时,此时已知的两串总和最大为maximal,计算L子串[i, i+L)总和,记为sum(i, L),则maximal = max(maximal, sum(i, L) + maxMSum[i+L])。注意计算子串总和时要利用上次的计算结果,以减少相加次数。然后再算L在M右边情况,取两种情况最大值为最终结果。时间复杂度O(n).
Approach 2: 大体与1相同,只是在求区间和时不累加,而是先算prefixSum,再算rangeSum
代码
approach 1
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& A, int L, int M) {
return max(helper(A, L, M), helper(A, M, L));
}
private:
int helper(vector<int>& A, int L, int M) {
int n = A.size();
vector<int> maxMSum(n); // maxMSum[i]表示[i, end)最大M的和
int start = n - M, prev = accumulate(A.begin()+start, A.end(), 0); // 最右M子串
maxMSum[start] = prev;
for(int i = start - 1; i >= L; i--) { // i >= L,给L子串留出空间
prev = prev + A[i] - A[i+M];
maxMSum[i] = max(prev, maxMSum[i+1]);
}
prev = accumulate(A.begin(), A.begin()+L, 0); // 最左L子串
int maximal = prev + maxMSum[L];
for(int i = 1; i < n - L; i++) {
prev = prev + A[i-1+L] - A[i-1];
maximal = max(maximal, prev + maxMSum[i+L]);
}
return maximal;
}
};
approach 2
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& A, int L, int M) {
int prev = 0;
for(auto x : A) {
prefixSum.push_back(prev += x);
}
return max(helper(L, M), helper(M, L));
}
private:
vector<int> prefixSum;
int rangeSum(int i, int j) {
return prefixSum[j] - (i == 0 ? 0 : prefixSum[i-1]);
}
// 设L在左,M在右
int helper(int L, int M) {
int n = prefixSum.size();
vector<int> maxMSum(n); // maxMSum[i]表示[i, end)最大M的和
int start = n - M;
maxMSum[start] = rangeSum(start, n-1); // 最右M子串
for(int i = start - 1; i >= L; i--) {
maxMSum[i] = max(rangeSum(i, i+M-1), maxMSum[i+1]);
}
int maximal = rangeSum(0, L-1) + maxMSum[L];
for(int i = 1; i < n - L; i++) {
maximal = max(maximal, rangeSum(i, i+L-1) + maxMSum[i+L]);
}
return maximal;
}
};