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] By Explore all Possible Subarrays - O(n2) Time and O(1) Space
The idea is to consider every possible subarray of the given array. For each subarray, we determine 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.
#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 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 };
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] Using Stack - O(n) Time and O(n) Space
Assume every element is the minimum element. So, each element has a range where it remains the minimum on both the left and the right side.
Now, the question transforms into: for every element, find the range where it will be the minimum.
How to find the range?
- If we keep expanding to the left while the current element is still the minimum, as soon as we encounter an element smaller than the current one, that marks the boundary of its left range.
- Similarly, if we expand to the right, the moment we find a smaller element, that becomes the boundary of its right range.
How to Count Subarrays in the Range?
Number of subarrays where A[i] is minimum= L × R
And its total contribution to the answer is:
Contribution of arr[i]= arr[i]× L× R
The idea is to find the range using Next Smaller and Previous Smaller elements (with the help of a monotonic stack) where the current element remains the minimum. Once the range is known, the contribution of that element to the total sum is calculated as arr[i] × L × R.
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int sumSubMins(vector<int>& arr) {
int n = arr.size();
vector<int> left(n), right(n);
stack<int> st;
// distance to previous smaller element
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();
// distance to next smaller or equal element
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);
}
int result = 0;
for (int i = 0; i < n; i++) {
// Contribution of current element
result += arr[i] * left[i] * right[i];
}
return result;
}
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> s1 = new Stack<>();
Stack<Integer> s2 = new Stack<>();
// Previous Smaller Element (strictly smaller)
for (int i = 0; i < n; i++) {
while (!s1.isEmpty() && arr[s1.peek()] > arr[i]) {
s1.pop();
}
left[i] = s1.isEmpty() ? (i + 1) : (i - s1.peek());
s1.push(i);
}
// Next Smaller Element (smaller or equal)
for (int i = n - 1; i >= 0; i--) {
while (!s2.isEmpty() && arr[s2.peek()] >= arr[i]) {
s2.pop();
}
right[i] = s2.isEmpty() ? (n - i) : (s2.peek() - i);
s2.push(i);
}
int result = 0;
for (int i = 0; i < n; i++) {
result += arr[i] * left[i] * right[i];
}
return result;
}
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
s1 = []
s2 = []
# Previous Smaller Element (strictly smaller)
for i in range(n):
while s1 and arr[s1[-1]] > arr[i]:
s1.pop()
left[i] = (i + 1) if not s1 else (i - s1[-1])
s1.append(i)
# Next Smaller Element (smaller or equal)
for i in range(n - 1, -1, -1):
while s2 and arr[s2[-1]] >= arr[i]:
s2.pop()
right[i] = (n - i) if not s2 else (s2[-1] - i)
s2.append(i)
result = 0
for i in range(n):
result += arr[i] * left[i] * right[i]
return result
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> s1 = new Stack<int>();
Stack<int> s2 = new Stack<int>();
// Previous Smaller Element (strictly smaller)
for (int i = 0; i < n; i++) {
while (s1.Count > 0 && arr[s1.Peek()] > arr[i]) {
s1.Pop();
}
left[i] = (s1.Count == 0) ? (i + 1) : (i - s1.Peek());
s1.Push(i);
}
// Next Smaller Element (smaller or equal)
for (int i = n - 1; i >= 0; i--) {
while (s2.Count > 0 && arr[s2.Peek()] >= arr[i]) {
s2.Pop();
}
right[i] = (s2.Count == 0) ? (n - i) : (s2.Peek() - i);
s2.Push(i);
}
int result = 0;
for (int i = 0; i < n; i++) {
result += arr[i] * left[i] * right[i];
}
return result;
}
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).fill(0);
const right = new Array(n).fill(0);
const s1 = [];
const s2 = [];
// Previous Smaller Element (strictly smaller)
for (let i = 0; i < n; i++) {
while (s1.length > 0 && arr[s1[s1.length - 1]] > arr[i]) {
s1.pop();
}
left[i] = (s1.length === 0) ? (i + 1) : (i - s1[s1.length - 1]);
s1.push(i);
}
// Next Smaller Element (smaller or equal)
for (let i = n - 1; i >= 0; i--) {
while (s2.length > 0 && arr[s2[s2.length - 1]] >= arr[i]) {
s2.pop();
}
right[i] = (s2.length === 0) ? (n - i) : (s2[s2.length - 1] - i);
s2.push(i);
}
let result = 0;
for (let i = 0; i < n; i++) {
result += arr[i] * left[i] * right[i];
}
return result;
}
// Driver code
const arr = [1, 2, 3, 4];
console.log(sumSubMins(arr));
Output
20
[Expected Approach 2] Using Dynamic Programming - O(n) Time and O(n) Space
The idea is to compute the index of the next smaller element to the right for each element using a monotonic stack (increasing stack). This helps us determine how far the current element remains the minimum in subarrays starting from its index.
#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