---
# System prepended metadata

title: Leetcode ---  Sum of Subarray Minimums
tags: [leetcode, medium, monotic stack, stack, array]

---

# 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`