给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。
由于答案可能很大,因此 返回答案模10^9 + 7  。
示例 1: 
**输入:** arr = [3,1,2,4]
**输出:** 17
**解释:** 子数组为 **** [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
示例 2: 
**输入:** arr = [11,81,94,43,3]
**输出:** 444
提示: 
1 <= arr.length <= 3 * 1041 <= arr[i] <= 3 * 104 
方法一:单调栈 考虑所有满足以数组 arr 中的某个元素 arr}[i] 为最右且最小的元素的子序列个数 C[i],那么题目要求求连续子数组的最小值之和即为 \sum_{i=0}^{n-1} \limits \textit{arr}[i] \times C[i],其中数组 arr 的长度为 n。我们必须假设当前元素为最右边且最小的元素,这样才可以构造互不相交的子序列,否则会出现多次计算,因为一个数组的最小值可能不唯一。
经过以上思考,我们只需要找到每个元素 arr}[i] 以该元素为最右且最小的子序列的数目 left}[i],以及以该元素为最左且最小的子序列的数目 right}[i],则以 arr}[i] 为最小元素的子序列的数目合计为 left}[i] \times \textit{right[i]。当然为了防止重复计算,我们可以设 arr}[i] 左边的元素都必须满足小于等于 arr}[i],arr}[i] 右边的元素必须满足严格小于 arr}[i]。当然这就变成求最小的下标 j \le i,且连续子序列中的元素 arr}[j], \textit{arr}[j+1], \cdots, \textit{arr}[i] 都满足大于等于 arr}[i],以及最大的下标 k > i 满足连续子序列 arr}[i + 1], \textit{arr}[i+1], \cdots, \textit{arr}[k] 都满足严格大于 arr}[i]。上述即转化为经典的单调栈问题,即求数组中当前元素 x 左边第一个小于 x 的元素以及右边第一个小于等于 x 的元素,关于「单调栈  」的算法细节,可以参考「496. 下一个更大元素 I 题解  」。
对于数组中每个元素 arr}[i],具体做法如下:
求左边第一个小于 arr}[i] 的元素:从左向右遍历数组,并维护一个单调递增的栈,遍历当前元素 arr}[i],如果遇到当前栈顶的元素大于等于 arr}[i] 则将其弹出,直到栈顶的元素小于 arr}[i],栈顶的元素即为左边第一个小于 arr}[i] 的元素 arr}[j],此时 left}[i] = i - j。
求右边第一个大于等于 arr}[i] 的元素:从右向左遍历数组,维护一个单调递增的栈,遍历当前元素 arr}[i],如果遇到当前栈顶的元素大于 arr}[i] 则将其弹出,直到栈顶的元素小于等于 arr}[i],栈顶的元素即为右边第一个小于等于 arr}[i] 的元素 arr}[k],此时 right}[i] = k - i。
连续子数组 arr}[j], \textit{arr}[j + 1], \cdots, \textit{arr}[k] 的最小元素即为 arr}[i],以 arr}[i] 为最小元素的连续子序列的数量为 (i - j) \times (k - i)。
 
根据以上结论可以知道,所有子数组的最小值之和即为 \sum_{i=0}^{n - 1} \limits \textit{arr}[i] \times \textit{left}[i] \times \textit{right}[i]。维护单调栈的过程线性的,因为只进行了线性次的入栈和出栈。
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 MOD = 10  ** 9  + 7  class  Solution :    def  sumSubarrayMins (self, arr: List [int ] ) -> int :         n = len (arr)         monoStack = []         left = [0 ] * n         right = [0 ] * n         for  i, x in  enumerate (arr):             while  monoStack and  x <= arr[monoStack[-1 ]]:                 monoStack.pop()             left[i] = i - (monoStack[-1 ] if  monoStack else  -1 )             monoStack.append(i)         monoStack = []         for  i in  range (n - 1 , -1 , -1 ):             while  monoStack and  arr[i] < arr[monoStack[-1 ]]:                 monoStack.pop()             right[i] = (monoStack[-1 ] if  monoStack else  n) - i             monoStack.append(i)         ans = 0          for  l, r, x in  zip (left, right, arr):             ans = (ans + l * r * x) % MOD         return  ans 
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class  Solution  {public :    int  sumSubarrayMins (vector<int >& arr)           int  n = arr.size ();         vector<int > monoStack;         vector<int > left (n) , right (n)  ;         for  (int  i = 0 ; i < n; i++) {             while  (!monoStack.empty () && arr[i] <= arr[monoStack.back ()]) {                 monoStack.pop_back ();             }             left[i] = i - (monoStack.empty () ? -1  : monoStack.back ());             monoStack.emplace_back (i);         }         monoStack.clear ();         for  (int  i = n - 1 ; i >= 0 ; i--) {             while  (!monoStack.empty () && arr[i] < arr[monoStack.back ()]) {                 monoStack.pop_back ();             }             right[i] = (monoStack.empty () ? n : monoStack.back ()) - i;             monoStack.emplace_back (i);         }         long  long  ans = 0 ;         long  long  mod = 1e9  + 7 ;         for  (int  i = 0 ; i < n; i++) {             ans = (ans + (long  long )left[i] * right[i] * arr[i]) % mod;          }         return  ans;     } }; 
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class  Solution  {    public  int  sumSubarrayMins (int [] arr)  {         int  n  =  arr.length;         Deque<Integer> monoStack = new  ArrayDeque <Integer>();         int [] left = new  int [n];         int [] right = new  int [n];         for  (int  i  =  0 ; i < n; i++) {             while  (!monoStack.isEmpty() && arr[i] <= arr[monoStack.peek()]) {                 monoStack.pop();             }             left[i] = i - (monoStack.isEmpty() ? -1  : monoStack.peek());             monoStack.push(i);         }         monoStack.clear();         for  (int  i  =  n - 1 ; i >= 0 ; i--) {             while  (!monoStack.isEmpty() && arr[i] < arr[monoStack.peek()]) {                 monoStack.pop();             }             right[i] = (monoStack.isEmpty() ? n : monoStack.peek()) - i;             monoStack.push(i);         }         long  ans  =  0 ;         final  int  MOD  =  1000000007 ;         for  (int  i  =  0 ; i < n; i++) {             ans = (ans + (long ) left[i] * right[i] * arr[i]) % MOD;          }         return  (int ) ans;     } } 
[sol1-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public  class  Solution  {    public  int  SumSubarrayMins (int [] arr         int  n = arr.Length;         Stack<int > monoStack = new  Stack<int >();         int [] left = new  int [n];         int [] right = new  int [n];         for  (int  i = 0 ; i < n; i++) {             while  (monoStack.Count > 0  && arr[i] <= arr[monoStack.Peek()]) {                 monoStack.Pop();             }             left[i] = i - (monoStack.Count == 0  ? -1  : monoStack.Peek());             monoStack.Push(i);         }         monoStack.Clear();         for  (int  i = n - 1 ; i >= 0 ; i--) {             while  (monoStack.Count > 0  && arr[i] < arr[monoStack.Peek()]) {                 monoStack.Pop();             }             right[i] = (monoStack.Count == 0  ? n : monoStack.Peek()) - i;             monoStack.Push(i);         }         long  ans = 0 ;         const  int  MOD = 1000000007 ;         for  (int  i = 0 ; i < n; i++) {             ans = (ans + (long ) left[i] * right[i] * arr[i]) % MOD;          }         return  (int ) ans;     } } 
[sol1-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 int  sumSubarrayMins (int * arr, int  arrSize)  {    int  monoStack[arrSize], left[arrSize], right[arrSize];     int  top = 0 ;     for  (int  i = 0 ; i < arrSize; i++) {         while  (top != 0  && arr[i] <= arr[monoStack[top - 1 ]]) {             top--;         }         left[i] = i - (top == 0  ? -1  : monoStack[top - 1 ]);         monoStack[top++] = i;     }     top = 0 ;     for  (int  i = arrSize - 1 ; i >= 0 ; i--) {         while  (top != 0  && arr[i] < arr[monoStack[top - 1 ]]) {             top--;         }         right[i] = (top == 0  ? arrSize : monoStack[top - 1 ]) - i;         monoStack[top++] = i;     }     long  long  ans = 0 ;     long  long  mod = 1e9  + 7 ;     for  (int  i = 0 ; i < arrSize; i++) {         ans = (ans + (long  long )left[i] * right[i] * arr[i]) % mod;      }     return  ans; } 
[sol1-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var  sumSubarrayMins = function (arr ) {    const  n = arr.length ;     let  monoStack = [];     const  left = new  Array (n).fill (0 );     const  right = new  Array (n).fill (0 );     for  (let  i = 0 ; i < n; i++) {         while  (monoStack.length  !== 0  && arr[i] <= arr[monoStack[monoStack.length  - 1 ]]) {             monoStack.pop ();         }         left[i] = i - (monoStack.length  === 0  ? -1  : monoStack[monoStack.length  - 1 ]);         monoStack.push (i);     }     monoStack = [];     for  (let  i = n - 1 ; i >= 0 ; i--) {         while  (monoStack.length  !== 0  && arr[i] < arr[monoStack[monoStack.length  - 1 ]]) {             monoStack.pop ();         }         right[i] = (monoStack.length  === 0  ? n : monoStack[monoStack.length  - 1 ]) - i;         monoStack.push (i);     }     let  ans = 0 ;     const  MOD  = 1000000007 ;     for  (let  i = 0 ; i < n; i++) {         ans = (ans + left[i] * right[i] * arr[i]) % MOD ;      }     return  ans; }; 
[sol1-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 func  sumSubarrayMins (arr []int ) int ) {    const  mod int  = 1e9  + 7      n := len (arr)     left := make ([]int , n)     right := make ([]int , n)     monoStack := []int {}     for  i, x := range  arr {         for  len (monoStack) > 0  && x <= arr[monoStack[len (monoStack)-1 ]] {             monoStack = monoStack[:len (monoStack)-1 ]         }         if  len (monoStack) == 0  {             left[i] = i + 1          } else  {             left[i] = i - monoStack[len (monoStack)-1 ]         }         monoStack = append (monoStack, i)     }     monoStack = []int {}     for  i := n - 1 ; i >= 0 ; i-- {         for  len (monoStack) > 0  && arr[i] < arr[monoStack[len (monoStack)-1 ]] {             monoStack = monoStack[:len (monoStack)-1 ]         }         if  len (monoStack) == 0  {             right[i] = n - i         } else  {             right[i] = monoStack[len (monoStack)-1 ] - i         }         monoStack = append (monoStack, i)     }     for  i, x := range  arr {         ans = (ans + left[i]*right[i]*x) % mod     }     return  } 
复杂度分析 
方法二:动态规划 设 s[j][i] 表示子数组 [\textit{arr}[j], \textit{arr}[j+1], \cdots,\textit{arr}[i]] 的最小值,则可以推出所有连续子数组的最小值之和为 \sum_{i=0}^{n-1} \limits \sum_{j=0}^{i} \limits s[j][i]。对于每个以 i 为最右的子数组最小值之和为 \sum_{j=0}^{i} \limits s[j][i]。我们只需要求出以每个元素 arr}[i] 为最右的子数组最小值之和,即可求出所有的子数组的最小值之和。每当我们减少 j 时,子序列的最小值可能会有关联,事实上我们可以观察到 s[j-1][i] =  \min(s[j][i], \textit{arr}[j-1])。
\begin{aligned}
上述序列的最小值分别为 [3, 3, 2, 2, 2, 1],可以发现重要点是 j = 5, j = 3, j = 0,分别是 j 从 i 开始向左移动遇到的最小值的位置。如下图所示:
设以 arr}[i] 为最右且最小的最长子序列长度为 k:
当 j >= i-k+1 时:连续子序列 [\textit{arr}[j],\textit{arr}[j+1], \cdots,\textit{arr}[i]] 的最小值为 arr}[i],即 s[j][i] = \textit{arr}[i]。
当 j < i-k + 1 时:连续子序列 [\textit{arr}[j],\textit{arr}[j+1], \cdots,\textit{arr}[i]] 的最小值一定比 arr}[i] 更小,通过分析可以知道它的最小值 s[j][i] = \min(s[j][i-k], \textit{arr}[i]) = s[j][i-k]。
 
则可以知道递推公式如下:
\begin{aligned}
我们令 dp}[i] = \sum_{j=0}^{i} \limits s[j][i],则上述等式转换为:
\textit{dp}[i] = \textit{dp}[i-k] + k \times \textit{arr}[i]
我们维护一个单调栈,很容易求出元素 x 的左边第一个比它小的元素,即求出以 x 为最右且最小的子序列的最大长度,子数组的最小值之和即为 \sum_{i=0}^{n-1} \limits \textit{dp}[i]。
具体解法过程如下:
[sol2-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 MOD = 10  ** 9  + 7  class  Solution :    def  sumSubarrayMins (self, arr: List [int ] ) -> int :         n = len (arr)         monoStack = []         dp = [0 ] * n         ans = 0          for  i, x in  enumerate (arr):             while  monoStack and  arr[monoStack[-1 ]] > x:                 monoStack.pop()             k = i - monoStack[-1 ] if  monoStack else  i + 1              dp[i] = k * x + (dp[i - k] if  monoStack else  0 )             ans = (ans + dp[i]) % MOD             monoStack.append(i)         return  ans 
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Solution  {public :    int  sumSubarrayMins (vector<int >& arr)           int  n = arr.size ();         long  long  ans = 0 ;         long  long  mod = 1e9  + 7 ;         stack<int > monoStack;         vector<int > dp (n)  ;         for  (int  i = 0 ; i < n; i++) {             while  (!monoStack.empty () && arr[monoStack.top ()] > arr[i]) {                 monoStack.pop ();             }             int  k = monoStack.empty () ? (i + 1 ) : (i - monoStack.top ());             dp[i] = k * arr[i] + (monoStack.empty () ? 0  : dp[i - k]);             ans = (ans + dp[i]) % mod;             monoStack.emplace (i);         }         return  ans;     } }; 
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution  {    public  int  sumSubarrayMins (int [] arr)  {         int  n  =  arr.length;         long  ans  =  0 ;         final  int  MOD  =  1000000007 ;         Deque<Integer> monoStack = new  ArrayDeque <Integer>();         int [] dp = new  int [n];         for  (int  i  =  0 ; i < n; i++) {             while  (!monoStack.isEmpty() && arr[monoStack.peek()] > arr[i]) {                 monoStack.pop();             }             int  k  =  monoStack.isEmpty() ? (i + 1 ) : (i - monoStack.peek());             dp[i] = k * arr[i] + (monoStack.isEmpty() ? 0  : dp[i - k]);             ans = (ans + dp[i]) % MOD;             monoStack.push(i);         }         return  (int ) ans;     } } 
[sol2-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  Solution  {    public  int  SumSubarrayMins (int [] arr         int  n = arr.Length;         long  ans = 0 ;         const  int  MOD = 1000000007 ;         Stack<int > monoStack = new  Stack<int >();         int [] dp = new  int [n];         for  (int  i = 0 ; i < n; i++) {             while  (monoStack.Count > 0  && arr[monoStack.Peek()] > arr[i]) {                 monoStack.Pop();             }             int  k = monoStack.Count == 0  ? (i + 1 ) : (i - monoStack.Peek());             dp[i] = k * arr[i] + (monoStack.Count == 0  ? 0  : dp[i - k]);             ans = (ans + dp[i]) % MOD;             monoStack.Push(i);         }         return  (int ) ans;     } } 
[sol2-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int  sumSubarrayMins (int * arr, int  arrSize)  {    long  long  ans = 0 ;     long  long  mod = 1e9  + 7 ;     int  monoStack[arrSize], dp[arrSize];     int  top = 0 ;     for  (int  i = 0 ; i < arrSize; i++) {         while  (top > 0  && arr[monoStack[top - 1 ]] > arr[i]) {             top--;         }         int  k = top == 0  ? (i + 1 ) : (i - monoStack[top - 1 ]);         dp[i] = k * arr[i] + (top == 0  ? 0  : dp[i - k]);         ans = (ans + dp[i]) % mod;         monoStack[top++] = i;     }     return  ans; } 
[sol2-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var  sumSubarrayMins = function (arr ) {    const  n = arr.length ;     let  ans = 0 ;     const  MOD  = 1000000007 ;     const  monoStack = [];     const  dp = new  Array (n).fill (0 );     for  (let  i = 0 ; i < n; i++) {         while  (monoStack.length  !== 0  && arr[monoStack[monoStack.length  - 1 ]] > arr[i]) {             monoStack.pop ();         }         const  k = monoStack.length  === 0  ? (i + 1 ) : (i - monoStack[monoStack.length  - 1 ]);         dp[i] = k * arr[i] + (monoStack.length  === 0  ? 0  : dp[i - k]);         ans = (ans + dp[i]) % MOD ;         monoStack.push (i);     }     return  ans; }; 
[sol2-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func  sumSubarrayMins (arr []int ) int ) {    const  mod int  = 1e9  + 7      n := len (arr)     monoStack := []int {}     dp := make ([]int , n)     for  i, x := range  arr {         for  len (monoStack) > 0  && arr[monoStack[len (monoStack)-1 ]] > x {             monoStack = monoStack[:len (monoStack)-1 ]         }         k := i + 1          if  len (monoStack) > 0  {             k = i - monoStack[len (monoStack)-1 ]         }         dp[i] = k * x         if  len (monoStack) > 0  {             dp[i] += dp[i-k]         }         ans = (ans + dp[i]) % mod         monoStack = append (monoStack, i)     }     return  } 
复杂度分析