三个无重叠子数组的最大和
难度:
标签:
题目描述
代码结果
运行时间: 48 ms, 内存: 18.0 MB
/*
* 思路:
* 1. 计算每个长度为 k 的子数组的和,使用 Streams 存储在 sums 列表中。
* 2. 使用 left 和 right 数组记录可以得到最大和的左边和右边的子数组起始位置。
* 3. 遍历 middle 子数组的起始位置,寻找使得总和最大的三个子数组组合。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int n = nums.length;
List<Integer> sums = IntStream.range(0, n - k + 1)
.map(i -> IntStream.range(i, i + k).map(j -> nums[j]).sum())
.boxed()
.collect(Collectors.toList());
int[] left = new int[n - k + 1];
int bestLeft = 0;
for (int i = 0; i <= n - k; i++) {
if (sums.get(i) > sums.get(bestLeft)) bestLeft = i;
left[i] = bestLeft;
}
int[] right = new int[n - k + 1];
int bestRight = n - k;
for (int i = n - k; i >= 0; i--) {
if (sums.get(i) >= sums.get(bestRight)) bestRight = i;
right[i] = bestRight;
}
int[] result = new int[3];
int maxSum = 0;
for (int mid = k; mid <= n - 2 * k; mid++) {
int l = left[mid - k];
int r = right[mid + k];
int total = sums.get(l) + sums.get(mid) + sums.get(r);
if (total > maxSum) {
maxSum = total;
result[0] = l;
result[1] = mid;
result[2] = r;
}
}
return result;
}
}
解释
方法:
本题解采用滑动窗口和动态规划的思想。首先,使用三个变量s1, s2, s3分别维护三个长度为k的子数组的和。然后,从第k * 2个元素开始遍历数组,每次向右移动一个元素,更新三个子数组的和。同时,使用mx1和mx12分别记录遍历过程中第一个子数组和前两个子数组的最大和,以及对应的起始下标idx1和idx12。最后,每次遍历时比较当前三个子数组的总和是否大于之前记录的最大值s,如果大于,则更新s和结果ans。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
如何保证三个子数组互不重叠?在代码中是如何实现的?
▷🦆
在更新子数组和的同时,如何保证每次更新都是基于最新的子数组起始位置?
▷🦆
在题解中提到,如果当前三个子数组的总和大于之前记录的最大值时才更新结果,那么是否有可能出现多个总和相同但起始位置不同的情况?如果有,如何确保返回字典序最小的结果?
▷🦆
题解中提到使用了滑动窗口和动态规划的思想,请问这里的动态规划是如何应用的?具体是在哪些部分体现的?
▷相关问题
买卖股票的最佳时机 III
给定一个数组,它的第 i
个元素是一支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:prices = [3,3,5,0,0,3,1,4] 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:
输入:prices = [1] 输出:0
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 105