Sum of Subarray Minimums - Monotonic Stack + DP
Problem Statement:
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: 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.
Example 2:
Input: arr = [11,81,94,43,3] Output: 444
Constraints:
1 <= arr.length <= 3 * 1041 <= arr[i] <= 3 * 104
Solution:
Intuition + Approach
The intuition is that while traversing, we will maintain a 1-D DP array such that
dp[i] = f(0,i) + f(1,i) + f(2,i) + ... + f(i,i)
where
f(j,i) = Minimum from indices j to i (inclusive)
Once we are done, we can add the dp array to get our answer.
Example
arr = [8,6,3,5,4,9,2]
For this example, we want that after we are done, the DP should look like:
dp = [8,12,9,14,17,26,14]
We can see that how this matches our expectation:
dp[0] = 8
dp[1] = 6+6
dp[2] = 3+3+3
dp[3] = 3+3+3+5
dp[4] = 3+3+3+4+4
dp[5] = 3+3+3+4+4+9
dp[6] = 2+2+2+2+2+2+2
As expected we can sum the dp array to get our answer 100.
How to create this DP array
We will use a monotonic stack (MS) for this. The basic setting for a MS is:
stack<int> stk;
for (int i=0; i<n; i++)
{
while (!stk).empty() && stk.top()>=A[i]) stk.pop();
stk.push(A[i]);
}
Here we will store the indices instead of the values. For each iteration in i, once we are done withe the popping, we can create dp[i] as follows:
-
If the stack is empty, it means the current element is the smallest of all elements in
(0,i)range. Hence,dp[i] = A[i]*(i+1)corresponding to ranges(0,i),(1,i),(2,i), ….,(i,i). -
If the stack is not empty and the top of the stack is
j, then, for the ranges(0,i),(1,i),(2,i), …,(j,i), the minimum element is stored indp[j](their sum) and for the ranges(j+1,i),(j+2,i), …,(i,i), the minimum element isA[i]. Hence,dp[i] = dp[j] + A[i]*(i-j)
Complexity
-
Time complexity: $O(n)$
-
Space complexity: $O(n)$
Code
#define ll long long int
class Solution {
public:
int sumSubarrayMins(vector<int>& arr)
{
int n = arr.size(), mod=1000000007;
ll res = 0;
vector<ll> dp(n,-1);
stack<int> stk;
for (int i=0; i<n; i++)
{
while (!stk.empty() && arr[i]<=arr[stk.top()]) stk.pop();
if (!stk.empty())
{
int j = stk.top();
dp[i] = dp[j] + arr[i]*(i-j);
}
else dp[i] = arr[i]*(i+1);
stk.push(i);
}
for (int x: dp) res+=x;
return (int)(res%mod);
}
};