子数组的最小值之和
难度:
标签:
题目描述
代码结果
运行时间: 83 ms, 内存: 19.2 MB
/*
* 思路:
* 1. 由于Java Stream对处理这种复杂的子数组最小值求和不太适用,
* 这里我们仍然使用单调栈的方法来实现,但用stream来简化代码结构。
*/
import java.util.*;
import java.util.stream.IntStream;
public class Solution {
public int sumSubarrayMins(int[] arr) {
int MOD = 1_000_000_007;
int n = arr.length;
int[] left = new int[n];
int[] right = new int[n];
Stack<Integer> stack = new Stack<>();
// Fill left array using stream
IntStream.range(0, n).forEach(i -> {
while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
stack.pop();
}
left[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(i);
});
// Clear the stack for reuse
stack.clear();
// Fill right array using stream
IntStream.iterate(n - 1, i -> i >= 0, i -> i - 1).forEach(i -> {
while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) {
stack.pop();
}
right[i] = stack.isEmpty() ? n : stack.peek();
stack.push(i);
});
// Calculate the result using stream
return (int) IntStream.range(0, n)
.mapToLong(i -> (long) arr[i] * (i - left[i]) * (right[i] - i) % MOD)
.reduce(0, (a, b) -> (a + b) % MOD);
}
}
解释
方法:
本题解使用单调栈的方法来找出所有子数组的最小值之和。首先,将原数组末尾添加一个0,以保证所有元素都能被正确处理。单调栈用于存储数组元素的索引,且栈中的元素对应的数组值将保持单调不增的顺序。对于每个元素,如果它小于或等于栈顶元素,那么栈顶元素及其之前的元素将依次出栈,直到栈顶元素小于当前元素。对于每个出栈的元素t,计算以arr[t]为最小值的子数组的数量,乘以arr[t],再累加到结果中。这样,每个元素在出栈时,可以算出以它为最小值的所有连续子数组对结果的贡献。最终,返回累加的结果,对1,000,000,007取模。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在数组末尾添加一个0,这样做有什么特殊的作用或优势?
▷🦆
在单调栈中使用-1作为哨兵元素有什么具体的意义或好处?
▷🦆
你提到对每个出栈的元素计算以arr[t]为最小值的子数组的数量,具体是如何计算的?
▷🦆
该算法中,如果栈顶元素等于当前元素,也会导致栈顶元素出栈,这样处理的原理是什么?
▷