2023-04-26每日一题
一、题目编号
1031. 两个非重叠子数组的最大和
二、题目链接
三、题目描述
给你一个整数数组 nums 和两个整数 firstLen 和 secondLen,请你找出并返回两个非重叠 子数组 中元素的最大和,长度分别为 firstLen 和 secondLen 。
长度为 firstLen 的子数组可以出现在长为 secondLen 的子数组之前或之后,但二者必须是不重叠的。
子数组是数组的一个 连续 部分。
四、解题代码
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& nums, int firstLen, int secondLen) {
int n = nums.size();
int dp[n+5];
int perfix_firstLen[n+5];
int perfix_secondLen[n+5];
int suffix_firstLen[n+5];
int suffix_secondLen[n+5];
memset(dp, 0, sizeof(dp));
memset(perfix_firstLen, 0, sizeof(perfix_firstLen));
memset(perfix_secondLen, 0, sizeof(perfix_secondLen));
memset(suffix_firstLen, 0, sizeof(suffix_firstLen));
memset(suffix_secondLen, 0, sizeof(suffix_secondLen));
for(int i = 1; i <= n; ++i){
dp[i] = (dp[i-1] + nums[i-1]);
}
for(int i = 0; i <= n; ++i){
if(i < firstLen){
perfix_firstLen[i] = -1;
} else{
perfix_firstLen[i] = max(perfix_firstLen[i-1], dp[i] - dp[i-firstLen]);
}
if(i < secondLen){
perfix_secondLen[i] = -1;
} else{
perfix_secondLen[i] = max(perfix_secondLen[i-1], dp[i] - dp[i-secondLen]);
}
}
for(int i = n; i >= 0; --i){
if(i + firstLen > n){
suffix_firstLen[i] = -1;
} else{
suffix_firstLen[i] = max(suffix_firstLen[i+1], dp[i+firstLen] - dp[i]);
}
if(i + secondLen > n){
suffix_secondLen[i] = -1;
} else{
suffix_secondLen[i] = max(suffix_secondLen[i+1], dp[i+secondLen] - dp[i]);
}
}
int res = 0;
for(int i = 0; i <= n; ++i){
if(perfix_firstLen[i] != -1 && suffix_secondLen[i] != -1){
res = max(res, perfix_firstLen[i] + suffix_secondLen[i]);
}
if(perfix_secondLen[i] != -1 && suffix_firstLen[i] != -1){
res = max(res, perfix_secondLen[i] + suffix_firstLen[i]);
}
}
return res;
}
};
五、解题思路
(1) 首先我们思考一个问题,分成的两段究竟怎么才能得到最大值。我们取数组下标中的一个位置i,任何不重叠的两端都可以分成i前一段(不包括i所指的元素)和i后一段(包括i所指的元素)。
(2) 按照(1)中所描述的思路,先算出前缀和,这样方便迅速求出长度固定的子数组和。
(3) 分别利用前后缀和,求出下标i前面长度为firstLen和secondLen的子数组最大和,求出下标i(包括下标i)后面长度为firstLen和secondLen的子数组最大和。
(4) 最后利用一遍线性枚举,求出最大值即可。