题目来源: 1031. 两个非重叠子数组的最大和
题目描述:
- 描述: 给你一个整数数组 nums 和两个整数 firstLen 和 secondLen,请你找出并返回两个非重叠 子数组 中元素的最大和,长度分别为 firstLen 和 secondLen 。 长度为 firstLen 的子数组可以出现在长为 secondLen 的子数组之前或之后,但二者必须是不重叠的。 子数组是数组的一个 连续 部分。
- 示例:
示例1:
输入:nums = [0,6,5,2,2,5,1,9,4], firstLen = 1, secondLen = 2
输出:20
- 解释:子数组的一种选择中,[9] 长度为 1,[6,5] 长度为 2。
示例2:
输入:nums = [3,8,1,3,2,1,8,9,0], firstLen = 3, secondLen = 2
输出:29
- 解释:子数组的一种选择中,[3,8,1] 长度为 3,[8,9] 长度为 2。
示例3:
输入:nums = [2,1,5,6,0,9,5,0,3,8], firstLen = 4, secondLen = 3
输出:31
- 解释:子数组的一种选择中,[5,6,0,9] 长度为 4,[0,3,8] 长度为 3。
思路
思路1 首先题目给出一个长度为n 的数组nums。现在我们需要返回两个长度分别为firstLen 和secondLen 的非重叠的子数组的最大和,firstLen+secondLen≤n,其中这两段子数组的前后顺序没有要求。
由于两段子数组的前后顺序没有区别,所以现在不妨设长度为firstLen 的子数组在长度为secondLen 的子数组前来计算此时的两段子数组的最大和。首先我们用nums[i,j] 来表示nums[i],nums[i+1],…,nums[j−1] 这一段子数组,并记sum(nums[l,r]) 表示子数组nums[l,r] 的和,dp[i] 为nums[0,i+1] 中长度为firstLen 的最大子数组和,若不存在长度为firstLen的子数组则为0。那么对于某一段长度为secondLen 的子数组nums[j,j+secondLen],0≤j<j+secondLen≤n,所以此时的两个数组的最大和为dp[j−1]+sum(nums[j,j+secondLen])
又因为dp[i]=max{dp[i−1],sum(nums[i+1−firstLen,i+1])}
由于现在长度为secondLen 在长度为firstLen 的后面,所以用两个大小为firstLen 和secondLen 的滑动窗口分别从位置0 和firstLen 同时开始从左往右滑动,并在过程中维护窗口中的和。因为对于∀i<firstLen−1,有dp[i]=0,并当i=firstLen−1 时为初始第一个窗口的和。那么在两个窗口从左到右移动的过程中,通过移动第一个窗口来更新dp 值,通过第二个窗口来计算此时的最大和,并记录移动过程中的最大值即可。
同理我们可以得到当secondLen 的子数组在长度为firstLen 的子数组前时,两段子数组的最大和,两种情况取较大值即为最终的答案。由于dp[i] 的求解只与dp[i−1] 有关,所以在实现的过程中我们可以通过「滚动数组」来进行空间优化。
具体实现1
class Solution {
public int maxSumTwoNoOverlap(int[] nums, int firstLen, int secondLen) {
return Math.max(help(nums, firstLen, secondLen), help(nums, secondLen, firstLen));
}
public int help(int[] nums, int firstLen, int secondLen) {
int suml = 0;
for (int i = 0; i < firstLen; ++i) {
suml += nums[i];
}
int maxSumL = suml;
int sumr = 0;
for (int i = firstLen; i < firstLen + secondLen; ++i) {
sumr += nums[i];
}
int res = maxSumL + sumr;
for (int i = firstLen + secondLen, j = firstLen; i < nums.length; ++i, ++j) {
suml += nums[j] - nums[j - firstLen];
maxSumL = Math.max(maxSumL, suml);
sumr += nums[i] - nums[i - secondLen];
res = Math.max(res, maxSumL + sumr);
}
return res;
}
}
复杂度分析1:
- 时间复杂度:O(nlogn),其中n 代表的是names 和heights 的长度。对indices 数组进行排序的时间复杂度为O(nlogn)。
- 空间复杂度:O(n),其中n 代表的是names 和heights 的长度。排序过程中所需要的栈空间为O(logn),创建indices 数组所需要的空间是O(n),对它们求和后空间复杂度渐进意义下等于O(n)。