Skip to content

Commit 1d1d2da

Browse files
authored
Merge pull request #70 from NEHA-AMIN/feature/subarray-sum-min
Solution #907 - Neha Amin - 15/07/2025
2 parents 2d8c867 + 86762bc commit 1d1d2da

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# 907. Sum of Subarray Minimums
2+
[](https://github.com/Dijkstra-Edu/LeetCode-Solutions/blob/master/Explanation-Template.md#problem-title)
3+
Difficulty: Medium
4+
Category: Arrays, Monotonic Stack, Dynamic Programming
5+
Leetcode Link: [Problem Link](https://leetcode.com/problems/sum-of-subarray-minimums/)
6+
7+
---
8+
9+
## 📝 Introduction
10+
Given an array arr of integers, the task is to compute the sum of the minimum element of every contiguous subarray.
11+
Since the total can be very large, the answer must be returned modulo 10^9 + 7.
12+
Constraints:
13+
- 1 <= arr.length <= 3 × 10^4
14+
- 1 <= arr[i] <= 3 × 10^4
15+
16+
---
17+
18+
## 💡 Approach & Key Insights
19+
We are asked to find the sum of all subarray minimums.
20+
A brute force approach would involve generating all subarrays and calculating their minimum, which is inefficient.
21+
To optimize, we observe that:
22+
- Each element arr[i] contributes to multiple subarrays as the minimum.
23+
- We can calculate how many subarrays each arr[i] will be the minimum for, using a monotonic stack.
24+
- With dynamic programming, we avoid recalculating overlapping subarray results.
25+
26+
---
27+
28+
## 🛠️ Breakdown of Approaches
29+
30+
### 1️⃣ Brute Force / Naive Approach
31+
32+
Explanation:
33+
Generate all subarrays, find the minimum of each, and add them to a running total.
34+
This method becomes inefficient for large arrays.
35+
36+
Time Complexity: O(n²) – Generating and traversing all subarrays
37+
Space Complexity: O(1) – No extra space beyond loop variables
38+
39+
Example/Dry Run:
40+
Example input: [3, 1, 2, 4]
41+
Step 1 → [3] → min = 3
42+
Step 2 → [3,1] → min = 1
43+
Step 3 → [3,1,2] → min = 1
44+
... → Total = 17
45+
46+
---
47+
48+
### 2️⃣ Optimized Approach
49+
50+
Explanation:
51+
Use a monotonic stack to track the previous less element for each index.
52+
Using a DP array res, where res[i] stores the sum of minimums for all subarrays ending at index i.
53+
We compute res[i] using:
54+
res[i] = res[j] + arr[i] × (i - j), where j is the index of the last element less than arr[i].
55+
56+
Time Complexity: O(n) – Each element is pushed and popped once
57+
Space Complexity: O(n) – For res array and stack
58+
59+
Example/Dry Run:
60+
Input: [3, 1, 2, 4]
61+
Step 1 → stack = [], res = [3, 0, 0, 0]
62+
Step 2 → pop 3, res[1] = 2
63+
Step 3 → stack = [1,2], res[2] = 4
64+
Step 4 → res[3] = 8
65+
Output: sum = 17
66+
67+
---
68+
69+
### 3️⃣ Best / Final Optimized Approach (if applicable)
70+
71+
Explanation:
72+
Same as optimized. There are no better solutions than O(n) using monotonic stacks for this problem.
73+
74+
Time Complexity: O(n) – Monotonic stack traversal
75+
Space Complexity: O(n) – Stack and DP array
76+
77+
Example/Dry Run:
78+
Example input: [3, 1, 2, 4]
79+
Step 1 → res = [3, 2, 4, 8]
80+
Step 2 → Sum = 3 + 2 + 4 + 8 = 17
81+
82+
---
83+
84+
## 📊 Complexity Analysis
85+
86+
| Approach | Time Complexity | Space Complexity |
87+
|----------------|------------------|------------------|
88+
| Brute Force | O(n²) | O(1) |
89+
| Optimized | O(n) | O(n) |
90+
| Best Approach | O(n) | O(n) |
91+
92+
---
93+
94+
## 📉 Optimization Ideas
95+
96+
- We could reduce space slightly by avoiding the res array and using a single accumulator.
97+
- However, the monotonic stack approach is already optimal in time and space for this problem's constraints.
98+
99+
---
100+
101+
## 📌 Example Walkthroughs & Dry Runs
102+
103+
Input: arr = [3, 1, 2, 4]
104+
Process:
105+
- i = 0 → arr[0] = 3 → res[0] = 3
106+
- i = 1 → pop stack → arr[1] = 1 → res[1] = 2
107+
- i = 2 → arr[2] > arr[1] → res[2] = res[1] + 2 × 1 = 4
108+
- i = 3 → res[3] = res[2] + 4 × 1 = 8
109+
res = [3, 2, 4, 8]
110+
Output = sum(res) = 17
111+
112+
---
113+
114+
## 🔗 Additional Resources
115+
116+
- [Monotonic Stack Guide](https://www.geeksforgeeks.org/dsa/introduction-to-monotonic-stack-2/)
117+
- [Dynamic Programming Basics](https://www.geeksforgeeks.org/dynamic-programming/)
118+
- [C++ STL Stack](https://cplusplus.com/reference/stack/stack/)
119+
120+
Author: Neha Amin
121+
Date: 19/07/2025
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class Solution {
2+
public:
3+
int sumSubarrayMins(vector<int>& arr) {
4+
stack<vector<int>> stack;
5+
vector<int> res(arr.size(), 0);
6+
7+
for (int i = 0; i < arr.size(); i++) {
8+
// use ">=" to deal with duplicate elements
9+
while (!stack.empty() && stack.top()[0] >= arr[i]) {
10+
stack.pop();
11+
}
12+
13+
int j = stack.empty() ? -1 : stack.top()[1];
14+
res[i] = stack.empty() ? arr[i] * (i + 1) : res[j] + arr[i] * (i - j);
15+
stack.push({arr[i], i});
16+
}
17+
18+
const long MOD = static_cast<long>(1e9 + 7);
19+
long ans = 0;
20+
21+
for (int i = 0; i < arr.size(); i++) {
22+
ans = (ans + static_cast<long>(res[i])) % MOD;
23+
}
24+
return static_cast<int>(ans);
25+
}
26+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class Solution {
2+
public int sumSubarrayMins(int[] arr) {
3+
Stack<int[]> stack = new Stack<>();
4+
long[] res = new long[arr.length];
5+
final long MOD = 1000000007L;
6+
7+
for (int i = 0; i < arr.length; i++) {
8+
// use ">=" to deal with duplicate elements
9+
while (!stack.isEmpty() && stack.peek()[0] >= arr[i]) {
10+
stack.pop();
11+
}
12+
13+
int j = stack.isEmpty() ? -1 : stack.peek()[1];
14+
res[i] = stack.isEmpty() ?
15+
((long) arr[i] * (i + 1)) % MOD :
16+
(res[j] + (long) arr[i] * (i - j)) % MOD;
17+
18+
stack.push(new int[]{arr[i], i});
19+
}
20+
21+
long ans = 0;
22+
23+
for (int i = 0; i < arr.length; i++) {
24+
ans = (ans + res[i]) % MOD;
25+
}
26+
27+
return (int) ans;
28+
}
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Solution:
2+
def sumSubarrayMins(self, arr: List[int]) -> int:
3+
stack = [] # keep index for the latest smaller values
4+
res = [0] * len(arr)
5+
6+
for i in range(len(arr)):
7+
while stack and arr[stack[-1]] > arr[i]:
8+
stack.pop()
9+
10+
j = stack[-1] if stack else -1
11+
res[i] = res[j] + (i - j) * arr[i]
12+
13+
stack.append(i)
14+
15+
return sum(res) % (10**9+7)

0 commit comments

Comments
 (0)