動機
之前有一題就是用左右兩邊的長度相乘算組合數,不過這題還要快速求出左右兩邊,所以就用了monotone stack
monotone stack有兩個用途
- previous less element
- next less element
Problem
Given an array of integers arr, find the sum of min(b)
, where b
ranges over every (contiguous) subarray of arr
. Since the answer may be large, return the answer modulo 109 + 7
.
Example 1:
Input: arr = [3,1,2,4]Output: 17Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4]. Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1.Sum is 17.
Example 2:
Input: arr = [11,81,94,43,3]Output: 444
Constraints:
1 <= arr.length <= 3 * 104
1 <= arr[i] <= 3 * 104
Sol
出左右兩邊,再一次組合起來
class Solution:
def sumSubarrayMins(self, arr: List[int]) -> int:
left = []
stk = []
for i in range(len(arr)):
count = 1
while stk and stk[-1][0] > arr[i]:
num, cnt = stk.pop()
count += cnt
left.append(count)
stk.append([arr[i],count])
right = []
stk = []
for i in reversed(range(len(arr))):
count = 1
while stk and stk[-1][0] >= arr[i]:
num, cnt = stk.pop()
count += cnt
right.append(count)
stk.append([arr[i],count])
return sum([l*a*r for l,a,r in zip(left,arr,right[::-1])]) % (10**9 + 7)
再整理stack時,可以直接算!! 因為stack下一個index就是左,現在比較大的就是右
不過要處理邊界問題,這裡用[0]+A+[0]
很神奇!!
class Solution:
def sumSubarrayMins(self, A):
res = 0
s = []
for i, x in enumerate(A):
while s and A[s[-1]] > x:
j = s.pop()
k = s[-1] if s else -1
res += A[j] * (i - j) * (j - k)
s.append(i)
return res % (10**9 + 7)