题目来源:https://leetcode-cn.com/problems/maximum-sum-of-3-non-overlapping-subarrays/
大致题意:
给一个数组 nums 和一个整数 k,在数组中找到互不重叠的三个长度为 k 的子数组,求出三个子数组可能有的最大和。返回最大和对应的三个子数组的左边界索引,如果有多个答案,返回字典序最小的
思路
一看是困难题我就怂了…
没想到今天的官方题解写的太棒,看了一下就懂了
这里就用自己的理解再写一遍
滑动窗口
题目中规定了子数组的长度为 k,那么显然可以使用滑动窗口:窗口大小为 k
这道题可以拆成子问题:在数组中找到一个长度为 k 的子数组的最大值、在数组中找到两个长度为 k 的子数组的最大值、在数组中找到三个长度为 k 的子数组的最大值
首先看如何在数组中找到一个长度为 k 的子数组的最大值:
- 使用长度为 k 的滑动窗口在数组上滑动,比较当前窗口内所有元素的和 sum1 与之前存的最大和 maxSum1,若当前和更大,那么更新最大和以及最大和对应的窗口左边界索引 maxSum1Idx
接下来看在数组中找到两个长度为 k 的子数组的最大值:
- 使用长度为 k 的滑动窗口在数组上滑动(起始位置为 0),比较当前窗口内所有元素的和 sum1 与之前存的最大和 maxSum1,若当前和更大,那么更新最大和以及最大和对应的窗口左边界索引 maxSum1Idx
- 使用长度为 k 的滑动窗口在数组上滑动(起始位置为 k),比较当前窗口内所有元素的和 sum2 加上上一步存的一个子数组的最大和 maxSum1 与之前存的两个子数组最大和 maxSum12,若当前和更大,那么更新最大和以及最大和对应的两个窗口左边界索引 maxSum12Idx1 和 maxSum12Idx2
- 同时滑动这两个窗口
那么同样的,可以求出三个长度为 k 的子数组的最大值:
- 使用长度为 k 的滑动窗口在数组上滑动(起始位置为 0),比较当前窗口内所有元素的和 sum1 与之前存的最大和 maxSum1,若当前和更大,那么更新最大和以及最大和对应的窗口左边界索引 maxSum1Idx
- 使用长度为 k 的滑动窗口在数组上滑动(起始位置为 k),比较当前窗口内所有元素的和 sum2 加上上一步存的一个子数组的最大和 maxSum1 与之前存的两个子数组最大和 maxSum12,若当前和更大,那么更新最大和以及最大和对应的两个窗口左边界索引 maxSum12Idx1 和 maxSum12Idx2
- 使用长度为 k 的滑动窗口在数组上滑动(起始位置为 2k),比较当前窗口内所有元素的和 sum3 加上上一步存的两个子数组的最大和 maxSum12 与之前存的两个子数组最大和 maxTotal,若当前和更大,那么更新最大和以及最大和对应的三个窗口左边界索引
代码:
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int[] ans = new int[3];
int n = nums.length;
int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
int sum2 = 0, maxSum12 = 0, maxSum12Idx1 = 0, maxSum12Idx2 = 0;
int sum3 = 0, maxTotal = 0;
for (int i = 2 * k; i < n; i++) {
// 更新窗口中三个子数组的和
sum1 += nums[i - 2 * k];
sum2 += nums[i - k];
sum3 += nums[i];
// 窗口已经形成
if (i >= 3 * k - 1) {
// 当前窗口的 一个子数组和 大于已有的最大值,更新
if (sum1 > maxSum1) {
maxSum1 = sum1;
maxSum1Idx = i - 3 * k + 1;
}
// 当前窗口的 两个子数组和 大于已有的最大值,更新
if (maxSum1 + sum2 > maxSum12) {
maxSum12 = maxSum1 + sum2;
maxSum12Idx1 = maxSum1Idx;
maxSum12Idx2 = i - 2 * k + 1;
}
// 当前窗口的 三个子数组和 大于已有的最大值,更新
if (maxSum12 + sum3 > maxTotal) {
maxTotal = maxSum12 + sum3;
ans[0] = maxSum12Idx1;
ans[1] = maxSum12Idx2;
ans[2] = i - k + 1;
}
// 滑动窗口,减去左边界的值
sum1 -= nums[i - 3 * k + 1];
sum2 -= nums[i - 2 * k + 1];
sum3 -= nums[i - k + 1];
}
}
return ans;
}