Browse curriculum

Sum of Subarray Minimums

Add up min(b) over every contiguous subarray b, in linear time, by counting with a monotonic stack how many subarrays each value is the minimum of.

Problem Understanding

Sum of Subarray Minimums: given an array of integers arr, find the sum of min(b) for every contiguous subarray b, modulo 10⁹ + 7.

Examples: [3,1,2,4] → 17 (minimums 3, 1, 2, 4, 1, 1, 2, 1, 1, 1); [11,81,94,43,3] → 444.

The Intuition: Count What Each Value Is the Minimum Of

There are O(n²) subarrays, but only n values that can be a minimum. Flip the question: for each value, how many subarrays is it the minimum of?

  1. Left reach: up to the nearest strictly smaller value on its left.
  2. Right reach: up to the nearest smaller-or-equal value on its right.
  3. Count: (choices of start) × (choices of end) = (i - L) × (R - i).

Both nearest-smaller boundaries come out of one monotonic stack pass, the same structure as Largest Rectangle in Histogram and Daily Temperatures.

Interactive Walkthrough

TINTED = WHERE THE POPPED VALUE IS THE MINIMUM

EMPTY STACK

arr

i

3

0

1

1

2

2

4

3

stack (bottom → top): value, index below

EMPTY

subarrays

:

added

:

total

0

 

For each value, count the subarrays it is the minimum of. The stack keeps indices with increasing values

Next

Read arr[0] = 3

Free preview: the first 5 of 15 steps

arr

When a value is popped, the stretch of the array where it is the minimum is tinted and its contribution is added. Try Ties to see equal values counted once.

Dry Run Table

Input: [3,1,2,4].

i Pops left right Added Total
1 3 (index 0) -1 1 3 × 1 × 1 = 3 3
4 (end) 4 (index 3) 2 4 4 × 1 × 1 = 4 7
4 (end) 2 (index 2) 1 4 2 × 1 × 2 = 4 11
4 (end) 1 (index 1) -1 4 1 × 2 × 3 = 6 17

Answer: 17.

The Solution Template

One pass with a sentinel at i = n. JavaScript and TypeScript use BigInt for the running sum, since the products can exceed 2⁵³ before the modulo.

Sum of Subarray Minimums Code
1var sumSubarrayMins = function(arr) {
2 const MOD = 1_000_000_007n;
3 const n = arr.length;
4 const stack = [];
5 let total = 0n;
6 for (let i = 0; i <= n; i++) {
7 while (stack.length && (i === n || arr[stack[stack.length - 1]] >= arr[i])) {
8 const mid = stack.pop();
9 const left = stack.length ? stack[stack.length - 1] : -1;
10 total += BigInt(arr[mid] * (mid - left) * (i - mid));
11 }
12 stack.push(i);
13 }
14 return Number(total % MOD);
15};

Edge Cases & Common Mistakes

  • Duplicates: use >= when popping (or > on the other side), never the same comparison on both sides, or ties are double counted.
  • Overflow: take the modulo as you go in Java/C++/C, or use 64-bit math.
  • Leftover stack: flush it with i = n so every value is counted.
  • One element: the answer is that element.
  • Brute force: O(n²) with a running minimum works for small n but times out at 3 × 10⁴.

Summary

Each value contributes value × (distance to the nearest smaller on the left) × (distance to the nearest smaller-or-equal on the right). A monotonic stack finds both distances as it pops. O(n) time and space.

More practice: DSA interview questions with answers · patterns cheat sheet

The approach, step by step

  1. Scan with a stack

    For i from 0 to n, keep a stack of indices whose values increase from bottom to top.

  2. Pop and count

    While the top's value is >= arr[i] (or i == n), pop mid; left is the new top or -1; add arr[mid] × (mid - left) × (i - mid).

  3. Push and finish

    Push i, and return the total modulo 10^9 + 7.

Frequently asked questions

How does counting contributions avoid listing all subarrays?

Every subarray has one minimum, so the answer is the sum over each value of value × (number of subarrays where it is the minimum). If arr[i]'s nearest smaller value on the left is at L and on the right at R, then arr[i] is the minimum of every subarray that starts after L and ends before R: (i - L) × (R - i) of them.


How does the stack find both neighbors at once?

The stack holds indices with increasing values. When arr[i] is smaller than or equal to the top, the top can never be the minimum past i, so it is popped: i is its right boundary, and the element left below it on the stack is its left boundary. Each index is pushed and popped once, so the pass is O(n).


Why >= on one side and < on the other?

With equal values, a subarray like [2, 2] has two candidate minimums. Popping on >= makes the right boundary 'smaller or equal', while the left boundary is the nearest strictly smaller value. That way each such subarray is credited to exactly one of the equal values, its rightmost one, and is counted once.


Why the extra iteration with i = n?

Values still on the stack at the end have nothing smaller to their right, so their right boundary is n. Treating i = n as a value smaller than everything flushes them through the same pop code instead of a second loop.

New to the technique behind this problem? Watch it run step by step:

Stack Visualization

Applying for software engineering roles? Free, no sign-up:

AI resume checker: match your resume to the job description