Sum of Subarray Ranges
Description:
You are given an integer array nums. The range of a subarray of nums is the difference between the largest and smallest element in the subarray.
Return the sum of all subarray ranges of nums.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [1,2,3]
Output: 4
Explanation: The 6 subarrays of nums are the following:
[1], range = largest - smallest = 1 - 1 = 0
[2], range = 2 - 2 = 0
[3], range = 3 - 3 = 0
[1,2], range = 2 - 1 = 1
[2,3], range = 3 - 2 = 1
[1,2,3], range = 3 - 1 = 2
So the sum of all ranges is 0 + 0 + 0 + 1 + 1 + 2 = 4.
Example 2:
Input: nums = [1,3,3]
Output: 4
Explanation: The 6 subarrays of nums are the following:
[1], range = largest - smallest = 1 - 1 = 0
[3], range = 3 - 3 = 0
[3], range = 3 - 3 = 0
[1,3], range = 3 - 1 = 2
[3,3], range = 3 - 3 = 0
[1,3,3], range = 3 - 1 = 2
So the sum of all ranges is 0 + 0 + 0 + 2 + 0 + 2 = 4.
Video Explanation

Approaches:
1. Monotonic Stack
The problem asks for the sum of all subarray ranges. We can optimize this using a Monotonic Stack by realizing that:
To find these sums efficiently, we need to determine how many subarrays a specific element acts as the maximum, and how many it acts as the minimum.
- For the Minimums: We use a monotonically increasing stack to find the Previous Smaller Element and Next Smaller Element.
- For the Maximums: We use a monotonically decreasing stack to find the Previous Greater Element and Next Greater Element.
- Handling Duplicates: To avoid double-counting subarrays when there are duplicate numbers, we use a strict inequality
<on one side and a non-strict inequality<=on the other.
- Time Complexity: because we iterate through the array a constant number of times. Each element is pushed and popped from the stack exactly once.
- Space Complexity: to store elements in the stack. In the worst-case scenario, the stack will store elements.
Monotonic Stack Solutions:
Solutions
- C++
- Java
- Python
- JavaScript
#include <vector>
using namespace std;
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long res = 0;
vector<int> st;
// Sum of Minimums
for (int i = 0; i <= n; ++i) {
while (!st.empty() && (i == n || nums[st.back()] > nums[i])) {
int j = st.back();
st.pop_back();
int left = j - (st.empty() ? -1 : st.back());
int right = i - j;
res -= 1LL * nums[j] * left * right;
}
st.push_back(i);
}
st.clear();
// Sum of Maximums
for (int i = 0; i <= n; ++i) {
while (!st.empty() && (i == n || nums[st.back()] < nums[i])) {
int j = st.back();
st.pop_back();
int left = j - (st.empty() ? -1 : st.back());
int right = i - j;
res += 1LL * nums[j] * left * right;
}
st.push_back(i);
}
return res;
}
};
import java.util.ArrayDeque;
import java.util.Deque;
class Solution {
public long subArrayRanges(int[] nums) {
int n = nums.length;
long res = 0;
Deque<Integer> st = new ArrayDeque<>();
// Sum of Minimums
for (int i = 0; i <= n; i++) {
while (!st.isEmpty() && (i == n || nums[st.peek()] > nums[i])) {
int j = st.pop();
int left = j - (st.isEmpty() ? -1 : st.peek());
int right = i - j;
res -= (long) nums[j] * left * right;
}
st.push(i);
}
st.clear();
// Sum of Maximums
for (int i = 0; i <= n; i++) {
while (!st.isEmpty() && (i == n || nums[st.peek()] < nums[i])) {
int j = st.pop();
int left = j - (st.isEmpty() ? -1 : st.peek());
int right = i - j;
res += (long) nums[j] * left * right;
}
st.push(i);
}
return res;
}
}
class Solution:
def subArrayRanges(self, nums: list[int]) -> int:
n = len(nums)
res = 0
# Sum of Minimums
stack = []
for i in range(n + 1):
while stack and (i == n or nums[stack[-1]] > nums[i]):
j = stack.pop()
left = j - stack[-1] if stack else j + 1
right = i - j
res -= nums[j] * left * right
stack.append(i)
# Sum of Maximums
stack = []
for i in range(n + 1):
while stack and (i == n or nums[stack[-1]] < nums[i]):
j = stack.pop()
left = j - stack[-1] if stack else j + 1
right = i - j
res += nums[j] * left * right
stack.append(i)
return res
/**
* @param {number[]} nums
* @return {number}
*/
var subArrayRanges = function(nums) {
const n = nums.length;
let res = 0;
let st = [];
// Sum of Minimums
for (let i = 0; i <= n; i++) {
while (st.length > 0 && (i === n || nums[st[st.length - 1]] > nums[i])) {
let j = st.pop();
let left = j - (st.length === 0 ? -1 : st[st.length - 1]);
let right = i - j;
res -= nums[j] * left * right;
}
st.push(i);
}
st = [];
// Sum of Maximums
for (let i = 0; i <= n; i++) {
while (st.length > 0 && (i === n || nums[st[st.length - 1]] < nums[i])) {
let j = st.pop();
let left = j - (st.length === 0 ? -1 : st[st.length - 1]);
let right = i - j;
res += nums[j] * left * right;
}
st.push(i);
}
return res;
};
Done with this topic? Mark it as complete to track your progress.
Related Practice Problems
Handpicked problems sharing similar algorithmic topic tags
Largest Rectangle in Histogram
Finding the area of the largest rectangle in a histogram using a monotonic stack approach.
Maximal Rectangle
Finding the largest rectangle containing only 1's in a binary matrix using a monotonic stack approach.
An Alternative Way
Solution for Codeforces 2241D: An Alternative Way, utilizing a prefix sum invariant approach.
💬 Discuss this page
Have a question or spot something confusing in "Sum of Subarray Ranges"? Ask below — it's backed by GitHub Discussions, so maintainers get notified like any other GitHub activity.