题目描述:

思路来源:
求数组中区间中最小数*区间所有数和的最大值
原文写的很好,本文附上Java版本代码,以及自己的注释理解
public int getMaxSum(int[] nums) {
int maxSum = Integer.MIN_VALUE;
int[] preSum = getPreSumArr(nums);
// 维持一个单调栈,存下标。 栈内下标对应元素单调非递减
LinkedList<Integer> stack = new LinkedList<>();
int index = 0;
while (index < nums.length) {
// 栈为空,或者当前值 >= 栈顶下标对应元素,证明栈顶元素还是最小元素
if (stack.isEmpty() || nums[index] >= nums[stack.peek()]) {
// 存下标
stack.push(index);
index++;
} else {
// nums[index] < nums[栈顶x] ,证明 x 可作为最小元素,右边界只可能到index - 1
// 开始对元素出栈
while (!stack.isEmpty() && nums[index] < nums[stack.peek()]) {
int curSum = 0;
int topIndex = stack.pop();
if (stack.isEmpty()) {
// 栈内最后一个元素,所以当前下标元素作最小值的区间为: [0,index - 1]
curSum = preSum[index - 1];
} else {
// 否则,是[topIndex, index - 1]
// 其实这里计算不一定对,比如连续压入几个x,但会在最底部的x处,获得正确的答案
curSum = preSum[index - 1] - preSum[topIndex - 1];
}
maxSum = Math.max(maxSum, nums[topIndex] * curSum);
}
}
}
// 此时栈内单调,所有栈内下标元素能作为最小值的右边界肯定是nums.length,只考虑左边界即可
while (!stack.isEmpty()) {
int curSum = 0;
int topIndex = stack.pop();
// 特判,栈内的最后一个元素,即整个数组最小就是它
if (stack.isEmpty()) {
// 整个数组和, [0,nums.length - 1]
curSum = preSum[nums.length - 1];
} else {
// [stack.peek() + 1, nums.length - 1]
curSum = preSum[nums.length - 1] - preSum[stack.peek()];
}
maxSum = Math.max(maxSum, nums[topIndex] * curSum);
}
return maxSum;
}
private int[] getPreSumArr(int[] nums) {
int n = nums.length;
// preSum[i] ,[0,i] 的和 (其实定义成 [0, i - 1] 也可以,具体细节不同,本处不实现
// 所以求 [i,j] 的和,应该是 preSum[j] - preSum[i - 1]
int[] preSum = new int[n];
int sum = 0;
for (int i = 0; i < n; i++) {
sum += nums[i];
preSum[i] = sum;
}
return preSum;
}
本文介绍了如何使用单调栈解决一个算法问题:在数组的每个区间内找到最小数,并计算其与区间内所有数之和的乘积,目标是最大化这个乘积。文中提供了一份详细的Java代码实现并附带注释解析。


被折叠的 条评论
为什么被折叠?



