# Leetcode --- Sum of Subarray Minimums ## 907. Sum of Subarray Minimums ### Description: 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 10^9 + 7. :::info Example : Input: arr = [3,1,2,4] Output: 17 Explanation: 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. ::: :::warning 此題的子陣列為連續型態, 因此總共只有n^2^個子陣列。 ::: ![](https://i.imgur.com/4zMn0if.png) ### 解法條列 1. 暴力解 O(n^3^) 2. 優化解 O(n) ### 解法細節 找出所以元素的左右小於元素索引位置, 即可用這兩個索引值計算該元素距離左右範圍, 會在幾個subset內為最小值, 並將之subset數乘上自身。 為了在線性時間O(n)找出所有左右索引, 使用資料結構: :::success monotonic stack ::: ### Python Solution 優化解 ```python= class Solution: def sumSubarrayMins(self, arr: List[int]) -> int: left_index_stack = [0 for _ in range(len(arr))] right_index_stack = [0 for _ in range(len(arr))] index_stack = [] # 找出右邊的小於值 for i,num in enumerate(arr): while(index_stack and arr[index_stack[-1]] >= num): tmp = index_stack.pop() right_index_stack[tmp] = i - tmp - 1 index_stack.append(i) while(index_stack): temp = index_stack.pop() right_index_stack[temp] = len(arr) - temp - 1 # 找出左邊的小於值 index_stack = [] i = len(arr)-1 while(i >= 0): while(index_stack and arr[index_stack[-1]] > arr[i]): tmp = index_stack.pop() left_index_stack[tmp] = tmp - i - 1 index_stack.append(i) i -= 1 while(index_stack): temp = index_stack.pop() left_index_stack[temp] = temp # 利用找出的左右小於值距離計算 ans = 0 for i in range(len(arr)): ans += ((left_index_stack[i]+1)*(right_index_stack[i]+1)*arr[i]) return ans%(10**9 + 7) ``` --- ```python=3 left_index_stack = [0 for _ in range(len(arr))] right_index_stack = [0 for _ in range(len(arr))] index_stack = [] ``` left_index_stack和right_index_stack用來存放對應索引值的左右距離 index_stack則是作為monotic stack來找出索引值位置 --- ```python= # 找出右邊的小於值 for i,num in enumerate(arr): while(index_stack and arr[index_stack[-1]] >= num): tmp = index_stack.pop() right_index_stack[tmp] = i - tmp - 1 index_stack.append(i) while(index_stack): temp = index_stack.pop() right_index_stack[temp] = len(arr) - temp - 1 ``` 這裡需要注意的是第7行的while迴圈,會處理在index_stack中的元素, 也就是沒有找到右邊有比較小的值. 可能因素有兩個: 1. 右邊沒有元素比較小 2. 右邊沒有其他元素了 因此為了正確紀錄距離,利用陣列長度以及其所在位置算出右邊的元素數量。 --- ```python=29 # 利用找出的左右小於值距離計算 ans = 0 for i in range(len(arr)): ans += ((left_index_stack[i]+1)*(right_index_stack[i]+1)*arr[i]) return ans%(10**9 + 7) ``` 利用左右距離計算並加總 --- 可改進部分為時間可以再縮短, 精簡操作的次數, 將程式碼合併起來。 ###### tags: `leetcode` `array` `medium` `stack` `monotic stack`