题目描述
给定一个整数数组 A
,找到 min(B)
的总和,其中 B
的范围为 A
的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
1 | 输入:[3,1,2,4] |
提示:
1 <= A <= 30000
1 <= 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.