Given an array arr[] of integers, find the sum of the minimum element of every possible subarray of array.
Examples:Â
Input: arr[] = [10, 20]Â
Output: 40
Explanation: Subarrays are [10], [20], [10, 20].Â
Minimums are [10, 20, 10]. Sum is 40.Input: arr[] = [1, 2, 3, 4]Â
Output: 20
Explanation: Subarrays are [1], [2], [3], [4], [1, 2], [1, 2, 3], [1, 2, 3, 4], [2, 3], [2, 3, 4], [3, 4].
Minimums are [1, 2, 3, 4, 1, 1, 1, 2, 2, 3]. Sum is 20.
Table of Content
[Naive Approach] Check All Subarrays - O(n^2) Time and O(1) Space
The idea is to consider every possible subarray of the given array. For each subarray, we find the minimum element and add it to our running sum. By doing this for all subarrays, the final result will be the sum of all minimum elements across all subarrays.
Working of the Approach:
- Start from each index as the beginning of a subarray.
- Extend the subarray one element at a time.
- Keep track of the minimum element in the current subarray.
- Add this minimum to the answer for every subarray.
- Return the final sum after considering all possible subarrays.
#include <iostream>
#include <vector>
using namespace std;
int sumSubMins(vector<int> &arr)
{
int n = arr.size();
int ans = 0;
// finding out the all possible subarray
for (int i = 0; i < n; i++)
{
int mini = arr[i];
for (int j = i; j < n; j++)
{
// select the minimum in the subarray
mini = min(mini, arr[j]);
// Adding that minimum element
// of the subarray to the answer
ans += mini;
}
}
return ans;
}
int main()
{
vector<int> arr = {1, 2, 3, 4};
cout << sumSubMins(arr) << endl;
return 0;
}
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.length;
int ans = 0;
// finding out the all possible subarrays
for (int i = 0; i < n; i++) {
int mini = arr[i];
for (int j = i; j < n; j++) {
// select the minimum in the subarray
mini = Math.min(mini, arr[j]);
// Adding that minimum element
// of the subarray to the answer
ans += mini;
}
}
return ans;
}
public static void main(String[] args) {
int[] arr = {1, 2,3,4};
System.out.println(sumSubMins(arr));
}
}
def sumSubMins(arr):
ans = 0
n = len(arr)
# finding out the all possible subarrays
for i in range(n):
mini = arr[i]
for j in range(i, n):
# select the minimum in the subarray
mini = min(mini, arr[j])
# Adding that minimum
# element of subarray to answer
ans += mini
return ans
if __name__ == "__main__":
arr = [1, 2,3,4]
print(sumSubMins(arr))
using System;
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.Length;
int ans = 0;
// Finding out all possible subarrays
for (int i = 0; i < n; i++) {
int mini = arr[i];
for (int j = i; j < n; j++) {
// Select the minimum in the subarray
mini = Math.Min(mini, arr[j]);
// Add that minimum element of the subarray to the answer
ans += mini;
}
}
return ans;
}
public static void Main(string[] args) {
int[] arr = { 1, 2, 3, 4 };
Console.WriteLine(sumSubMins(arr));
}
}
function sumSubMins(arr) {
let ans = 0;
const n = arr.length;
// finding out the all possible subarrays
for (let i = 0; i < n; i++) {
// To store the minimum element
let mini = arr[i];
for (let j = i; j < n; j++) {
// Finding the minimum element of the subarray
mini = Math.min(mini, arr[j]);
// Adding that minimum element
// of the subarray to the answer
ans += mini;
}
}
return ans;
}
// Driver Code
const arr = [ 1, 2, 3, 4 ];
console.log(sumSubMins(arr));
Output
20
[Expected Approach 1] Monotonic Stack - O(n) Time and O(n) Space
The idea is to find the range where each element remains the minimum using its Previous Smaller and Next Smaller elements with a monotonic stack.
For each element, the number of possible subarrays is computed by the choices on its left and right, so its contribution is calculated as arr[i] * L * R.
Working of the Approach:
- Consider each element as the minimum and find the range where it remains the smallest.
- Find the Previous Smaller Element (PSE) to determine the left boundary.
- Find the Next Smaller Element (NSE) to determine the right boundary.
- If there are L choices on the left and R choices on the right, the element is the minimum in L * R subarrays.
- Add arr[i] * L * R to the answer.
- Use a monotonic stack to find PSE and NSE efficiently.
Consider each element as the minimum. For every arr[i], find the range in which it remains the minimum.
How to find the range?
- Move left until a smaller element is found. This determines the left boundary.
- Move right until a smaller element is found. This determines the right boundary.
- Let L be the number of choices on the left and R be the number of choices on the right.
How to count its contribution?
- Number of subarrays where arr[i] is minimum = L * R
- Contribution of arr[i] = arr[i] * L * R
#include <bits/stdc++.h>
using namespace std;
int sumSubMins(vector<int> &arr) {
int n = arr.size();
vector<int> left(n), right(n);
stack<int> st;
// Find the previous smaller element for each index.
for (int i = 0; i < n; i++) {
while (!st.empty() && arr[st.top()] >= arr[i])
st.pop();
left[i] = st.empty() ? i + 1 : i - st.top();
st.push(i);
}
while (!st.empty())
st.pop();
// Find the next smaller or equal element for each index.
for (int i = n - 1; i >= 0; i--) {
while (!st.empty() && arr[st.top()] > arr[i])
st.pop();
right[i] = st.empty() ? n - i : st.top() - i;
st.push(i);
}
long long ans = 0;
for (int i = 0; i < n; i++)
ans += 1LL * arr[i] * left[i] * right[i];
return ans;
}
int main() {
vector<int> arr = {1, 2, 3, 4};
cout << sumSubMins(arr) << endl;
return 0;
}
import java.util.Stack;
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.length;
int[] left = new int[n];
int[] right = new int[n];
Stack<Integer> st = new Stack<>();
// Find the previous smaller element for each index.
for (int i = 0; i < n; i++) {
while (!st.isEmpty() && arr[st.peek()] >= arr[i])
st.pop();
left[i] = st.isEmpty() ? i + 1 : i - st.peek();
st.push(i);
}
st.clear();
// Find the next smaller or equal element for each index.
for (int i = n - 1; i >= 0; i--) {
while (!st.isEmpty() && arr[st.peek()] > arr[i])
st.pop();
right[i] = st.isEmpty() ? n - i : st.peek() - i;
st.push(i);
}
long ans = 0;
for (int i = 0; i < n; i++)
ans += (long) arr[i] * left[i] * right[i];
return (int) ans;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
System.out.println(sumSubMins(arr));
}
}
def sumSubMins(arr):
n = len(arr)
left = [0] * n
right = [0] * n
st = []
# Find the previous smaller element for each index.
for i in range(n):
while st and arr[st[-1]] >= arr[i]:
st.pop()
left[i] = i + 1 if not st else i - st[-1]
st.append(i)
st.clear()
# Find the next smaller or equal element for each index.
for i in range(n - 1, -1, -1):
while st and arr[st[-1]] > arr[i]:
st.pop()
right[i] = n - i if not st else st[-1] - i
st.append(i)
ans = 0
for i in range(n):
ans += arr[i] * left[i] * right[i]
return ans
if __name__ == "__main__":
arr = [1, 2, 3, 4]
print(sumSubMins(arr))
using System;
using System.Collections.Generic;
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.Length;
int[] left = new int[n];
int[] right = new int[n];
Stack<int> st = new Stack<int>();
// Find the previous smaller element for each index.
for (int i = 0; i < n; i++) {
while (st.Count > 0 && arr[st.Peek()] >= arr[i])
st.Pop();
left[i] = st.Count == 0 ? i + 1 : i - st.Peek();
st.Push(i);
}
st.Clear();
// Find the next smaller or equal element for each index.
for (int i = n - 1; i >= 0; i--) {
while (st.Count > 0 && arr[st.Peek()] > arr[i])
st.Pop();
right[i] = st.Count == 0 ? n - i : st.Peek() - i;
st.Push(i);
}
long ans = 0;
for (int i = 0; i < n; i++)
ans += (long) arr[i] * left[i] * right[i];
return (int) ans;
}
static void Main() {
int[] arr = {1, 2, 3, 4};
Console.WriteLine(sumSubMins(arr));
}
}
function sumSubMins(arr) {
const n = arr.length;
const left = new Array(n);
const right = new Array(n);
const st = [];
// Find the previous smaller element for each index.
for (let i = 0; i < n; i++) {
while (st.length > 0 && arr[st[st.length - 1]] >= arr[i])
st.pop();
left[i] = st.length === 0
? i + 1
: i - st[st.length - 1];
st.push(i);
}
st.length = 0;
// Find the next smaller or equal element for each index.
for (let i = n - 1; i >= 0; i--) {
while (st.length > 0 && arr[st[st.length - 1]] > arr[i])
st.pop();
right[i] = st.length === 0
? n - i
: st[st.length - 1] - i;
st.push(i);
}
let ans = 0;
for (let i = 0; i < n; i++)
ans += arr[i] * left[i] * right[i];
return ans;
}
// Driver Code
const arr = [1, 2, 3, 4];
console.log(sumSubMins(arr));
Output
20
[Expected Approach 2] Dynamic Programming - O(n) Time and O(n) Space
The idea is to calculate the contribution of all subarrays starting at each index using dynamic programming.
For every element, find the Next Smaller Element (NSE) using a monotonic stack. This tells us how far the current element remains the minimum. We then reuse the result of the subarray starting at the NSE to avoid recomputing overlapping subarrays.
Working of the Approach:
- Traverse the array from right to left.
- Use a monotonic stack to find the Next Smaller Element for each index.
- If no smaller element exists, the current element remains the minimum until the end.
- Calculate the contribution of all subarrays starting at the current index.
- If an NSE exists at index j, use the previously computed result for j.
- Store the result for each index in a DP array and add it to the answer.
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int sumSubMins(vector<int>& arr) {
int n = arr.size();
vector<int> dp(n, 0);
vector<int> right(n);
vector<int> st;
// Initialize right[] to self indices
for (int i = 0; i < n; i++) right[i] = i;
// Find index of next
// smaller element on the right
for (int i = 0; i < n; i++) {
while (!st.empty() && arr[i] < arr[st.back()]) {
right[st.back()] = i;
st.pop_back();
}
st.push_back(i);
}
// Fill dp[] from right to left
dp[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
int r = right[i];
if (r == i) {
dp[i] = (n - i) * arr[i];
} else {
dp[i] = (r - i) * arr[i] + dp[r];
}
}
return accumulate(dp.begin(), dp.end(), 0);
}
int main() {
vector<int> arr = {1,2,3,4};
cout << sumSubMins(arr) << endl;
return 0;
}
import java.util.Stack;
import java.util.Arrays;
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.length;
int[] dp = new int[n];
int[] right = new int[n];
Stack<Integer> st = new Stack<>();
// Initialize right[] to self indices
for (int i = 0; i < n; i++) right[i] = i;
// Find index of next smaller
// element on the right
for (int i = 0; i < n; i++) {
while (!st.isEmpty() && arr[i] < arr[st.peek()]) {
right[st.pop()] = i;
}
st.push(i);
}
// Fill dp[] from right to left
dp[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
int r = right[i];
if (r == i) {
dp[i] = (n - i) * arr[i];
} else {
dp[i] = (r - i) * arr[i] + dp[r];
}
}
int sum = 0;
for (int val : dp) sum += val;
return sum;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
System.out.println(sumSubMins(arr));
}
}
def sumSubMins(arr):
n = len(arr)
dp = [0] * n
right = [i for i in range(n)]
st = []
# Find index of next
# smaller element on the right
for i in range(n):
while st and arr[i] < arr[st[-1]]:
right[st.pop()] = i
st.append(i)
# Fill dp[] from right to left
dp[n - 1] = arr[n - 1]
for i in range(n - 2, -1, -1):
r = right[i]
if r == i:
dp[i] = (n - i) * arr[i]
else:
dp[i] = (r - i) * arr[i] + dp[r]
return sum(dp)
if __name__ == "__main__":
arr = [1, 2, 3, 4]
print(sumSubMins(arr))
using System;
using System.Collections.Generic;
class GFG {
static int sumSubMins(int[] arr) {
int n = arr.Length;
int[] dp = new int[n];
int[] right = new int[n];
Stack<int> st = new Stack<int>();
// Initialize right[] to self indices
for (int i = 0; i < n; i++) right[i] = i;
// Find index of next
// smaller element on the right
for (int i = 0; i < n; i++) {
while (st.Count > 0 && arr[i] < arr[st.Peek()]) {
right[st.Pop()] = i;
}
st.Push(i);
}
// Fill dp[] from right to left
dp[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
int r = right[i];
if (r == i) {
dp[i] = (n - i) * arr[i];
}
else {
dp[i] = (r - i) * arr[i] + dp[r];
}
}
int sum = 0;
foreach (int val in dp) sum += val;
return sum;
}
static void Main() {
int[] arr = { 1, 2, 3, 4 };
Console.WriteLine(sumSubMins(arr));
}
}
function sumSubMins(arr) {
const n = arr.length;
const dp = new Array(n).fill(0);
const right = Array.from({ length: n }, (_, i) => i);
const st = [];
// Find index of next
// smaller element on the right
for (let i = 0; i < n; i++) {
while (st.length > 0 && arr[i] < arr[st[st.length - 1]]) {
right[st.pop()] = i;
}
st.push(i);
}
// Fill dp[] from right to left
dp[n - 1] = arr[n - 1];
for (let i = n - 2; i >= 0; i--) {
const r = right[i];
if (r === i) {
dp[i] = (n - i) * arr[i];
} else {
dp[i] = (r - i) * arr[i] + dp[r];
}
}
return dp.reduce((acc, val) => acc + val, 0);
}
// Driver code
const arr = [1, 2, 3, 4];
console.log(sumSubMins(arr));
Output
20