题目描述
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
1 | 输入:[3,1,2,4] |
提示:
1 <= A <= 300001 <= A[i] <= 30000
题解
单调栈
思路
- 设置两个数组
left[]和right[],left[i]表示A[i]左侧第一个比它小的元素(Previous Less Element,简称 PLE)位置,right[i]表示A[i]右侧第一个比它小的元素(Next Less Element,简称 NLE)位置。-1表示左侧或右侧没有比它小的元素。 - 通过单调栈 (Monotone Stack) 找出这两个数组。
- 通过
A[i]和它的 PLE 和 NLE 之间的距离,可以计算出A[i]在子数组中出现的次数。 - 例
1 | A[]: [ 2, 9, 7, 8, 3, 4, 6, 1 ] |
- 以
3为例
A[]: [ 2, 9, 7, 8, 3, 4, 6, 1 ]
| ^ |
PLE of 3 NLE of 3
└-----------┘
left distance: 4
└-------┘
right distance: 3
3和它的 PLE 之间距离是 4,和它的 NLE 之间距离是 3。以3为最小元素的子数组共有4 * 3 = 12个。分别如下:
1 | 9, 7, 8, 3 |
- 子数组的和中关于
3的和为3 * (4 * 3)。 - 假设
leftDistance[i]和rightDistance[i]分别为A[i]与它的 PLE 和 NLE 之间的距离。如果left[i] == -1则距离为 1。 - 由此可以计算出最终结果为
sum(A[i] * leftDistance[i] * rightDistance[i])
代码
1 | var sumSubarrayMins = function(A) { |
复杂度
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
暴力法
思路
- 找出所有连续子数组中最小值,然后相加。
代码
1 | var sumSubarrayMins = function(A) { |
复杂度
- 时间复杂度:$O(n^2)$
- 空间复杂度:$O(1)$
参考链接
- stack solution with very detailed explanation step by step, LeetCode Discuss.