又一次见识到了与大佬的差距。
首先自己的做法:
将以每个数字为结尾的长度为L或者M的连续子数组的和记录下来,然后分别计算L在前面和M在前面的情况。其实就是暴力法。
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& A, int L, int M) {
int sz = A.size();
if (L + M > sz)
return -1;
vector<int> LSum(sz, 0), MSum(sz, 0);
int window = 0;
int i = 0;
while (i < sz) {
window += A[i];
if (i >= L)
window -= A[i-L];
LSum[i] = window;
++i;
}
i = 0;
window = 0;
while (i < sz) {
window += A[i];
if (i >= M)
window -= A[i-M];
MSum[i] = window;
++i;
}
int maxSum = 0;
for (i = L-1; i < sz-M; ++i)
for (int j = i+M; j < sz; ++j)
maxSum = max(maxSum, LSum[i] + MSum[j]);
for (i = M-1; i < sz-L; ++i)
for (int j = i+L; j < sz; ++j)
maxSum = max(maxSum, MSum[i] + LSum[j]);
return maxSum;
}
};
方法二:
大佬的方法。
1.首先不是用滑动窗口来计算每一段的和了,而是记录所有的前缀和,然后用的时候减就行了。
2.维持两个变量:
LMax:在当前M个之前的最大的L个数字的连续和。
MMax:同理。
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& A, int L, int M) {
for (int i = 1; i < A.size(); ++i)
A[i] += A[i-1];
int res = A[L+M-1], LMax = A[L-1], MMax = A[M-1];
for (int i = L+M; i < A.size(); ++i) {
LMax = max(LMax, A[i-M] - A[i-M-L]);
MMax = max(MMax, A[i-L] - A[i-L-M]);
res = max(res, max(A[i]-A[i-L]+MMax, A[i]-A[i-M]+LMax));
}
return res;
}
};
在每个位置计算:
1.以当前位置结尾的L长度的连续和以及之前的最大的M长度的连续和的和
2.以当前位置结尾的M长度的连续和以及之前的最大的L长度的连续和的和
真的很简洁了。
这一题需要我注意的一点是:
其实两种方法中求区间和的方法分别是滑动窗口(我的)和前缀和(大佬的)。其实这一题用前缀和比较好。因为窗口大小是知道的, 不用怎么“滑动”,滑动窗口比较适合那种窗口大小不固定的题目吧。