Maximize sum of given array after removing valleys
Last Updated :
22 Sep, 2022
Given an array arr[] of integers of size N, the task is to maximize the sum of the array after removing valleys from the array when only reducing the value of an element is allowed i.e. the new formed array should not contain any element which has greater value after modification.
Valleys:- An index j is considered as a valley point if arr[i] > arr[j] and arr[ k ] > arr[ j ] given that (i < j < k).
Examples:
Input : arr[] = { 5, 10, 15 }
Output: 30
Explanation: As array does not contain any valley, so there is no need to reduce any element.
Input : arr[] = { 8, 1, 10, 1, 8 }
Output : 14
Explanation: new_arr=> [1, 1, 10, 1, 1] and sum = 14, new_arr can also be constructed as [8, 1, 1, 1, 1], but the sum will be less.
Naive Approach: Consider each element as a peak element and start in decreasing order in both directions of the peak element.
If arr = [8, 1, 10, 1, 8 ]
Consider 10 as peak element and then the final array would like [ 1, 1, 10, 1, 1]
Time Complexity: O(N2)
Auxiliary Space: O(1)
Efficient Approach: Instead of taking each index as a peak point. Calculate prefix and suffix sum array for each index(idx). Prefix array can be used to store the sum of heights from 0 . . . idx satisfying the condition that there is no valley on the left side and idx has the peak element. Suffix sum array also satisfy the same conditions for the suffix of the index idx.
The element at an index can span in the left direction, till a smaller element is found, assuming that the current element is the highest one. The next smaller element using stack concept can be used here with minor changes.
Follow the steps mentioned below:
- Build the prefix sum (left) and suffix sum (right) array. There will be two case while building the arrays. Consider the cases for prefix sum array below. Same is applicable for suffix sum array also.
- The current element is the smallest amongst all elements till now.
So, left [ curr_idx ] = ( i +1 ) * arr[i] . Here (i + 1) denotes the range .
- There is a smaller element with small_idx, on the left side.
So, left [ curr_idx] = left[ small_idx ] + (current_idx – small_idx) *arr[i]
Using same method right sum array can be calculated .
- Now, iterate through each index and calculate answer = left[idx] + right[idx] – arr[idx]
Note: arr[idx] is subtracted, because arr[ idx ] is added in left[] as well as right[] array.
See the illustration below for better understanding.
Illustration:
Consider the example arr[] = { 5, 1, 8 }
While building the prefix sum array
At index = 0: There is no element in the left[0] = 5.
Index = 1: 1 is the smallest among all from the left. So, left[1] = 1 * 2 = 2.
Index = 2: 8 has smaller element 1 at index 1. So left[2] = left[1] + 8*(2 – 1) = 2 + 8 = 10.
So left[] = {5, 2, 10}. Similarly right[] = {7, 2, 8}.
Now while traversing to calculate the answer the values from index 0, 1 and 2 are (5 + 7 – 5), (2 + 2 – 1), (10 + 8 – 8) respectively. The maximum among these is 10. So the answer is 10.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int solve(vector< int >& arr)
{
int n = arr.size();
vector< int > left(n, 0);
vector< int > right(n, 0);
vector< int > stack;
for ( int i = 0; i < n; i++) {
int curr = arr[i];
while (stack.size() != 0
&& arr[stack[stack.size() - 1]] >= curr) {
stack.pop_back();
}
if (stack.size() == 0)
left[i] = (i + 1) * (arr[i]);
else {
int small_idx = stack[stack.size() - 1];
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.push_back(i);
}
stack.clear();
for ( int i = n - 1; i > -1; i--) {
int curr = arr[i];
while (stack.size() != 0
&& arr[stack[stack.size() - 1]] >= curr) {
stack.pop_back();
}
if (stack.size() == 0)
right[i] = (n - i) * (arr[i]);
else {
int small_idx = stack[stack.size() - 1];
right[i] = right[small_idx]
+ (small_idx - i) * (arr[i]);
}
stack.push_back(i);
}
int ans = 0;
for ( int i = 0; i < n; i++) {
int curr = left[i] + right[i] - arr[i];
ans = max(ans, curr);
}
return (ans);
}
int main()
{
vector< int > arr = { 5, 1, 8 };
cout << solve(arr);
return 0;
}
|
Java
import java.util.*;
class GFG{
static int solve( int [] arr)
{
int n = arr.length;
int []left = new int [n];
int []right = new int [n];
Vector<Integer> stack = new Vector<Integer>();
for ( int i = 0 ; i < n; i++) {
int curr = arr[i];
while (stack.size() != 0
&& arr[stack.get(stack.size() - 1 )] >= curr) {
stack.remove(stack.size() - 1 );
}
if (stack.size() == 0 )
left[i] = (i + 1 ) * (arr[i]);
else {
int small_idx = stack.get(stack.size() - 1 );
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.add(i);
}
stack.clear();
for ( int i = n - 1 ; i > - 1 ; i--) {
int curr = arr[i];
while (stack.size() != 0
&& arr[stack.get(stack.size() - 1 )] >= curr) {
stack.remove(stack.size() - 1 );
}
if (stack.size() == 0 )
right[i] = (n - i) * (arr[i]);
else {
int small_idx = stack.get(stack.size() - 1 );
right[i] = right[small_idx]
+ (small_idx - i) * (arr[i]);
}
stack.add(i);
}
int ans = 0 ;
for ( int i = 0 ; i < n; i++) {
int curr = left[i] + right[i] - arr[i];
ans = Math.max(ans, curr);
}
return (ans);
}
public static void main(String[] args)
{
int [] arr = { 5 , 1 , 8 };
System.out.print(solve(arr));
}
}
|
Python3
def solve(arr):
n = len (arr)
left = [ 0 ] * (n)
right = [ 0 ] * (n)
stack = []
for i in range (n):
curr = arr[i]
while (stack and
arr[stack[ - 1 ]] > = curr):
stack.pop()
if ( len (stack) = = 0 ):
left[i] = (i + 1 ) * (arr[i])
else :
small_idx = stack[ - 1 ]
left[i] = left[small_idx] \
+ (i - small_idx) * (arr[i])
stack.append(i)
stack.clear()
for i in range (n - 1 , - 1 , - 1 ):
curr = arr[i]
while (stack and
arr[stack[ - 1 ]] > = curr):
stack.pop()
if ( len (stack) = = 0 ):
right[i] = (n - i) * (arr[i])
else :
small_idx = stack[ - 1 ]
right[i] = right[small_idx] \
+ (small_idx - i) * (arr[i])
stack.append(i)
ans = 0
for i in range (n):
curr = left[i] + right[i] - arr[i]
ans = max (ans, curr)
return (ans)
if __name__ = = "__main__" :
arr = [ 5 , 1 , 8 ]
print (solve(arr))
|
C#
using System;
using System.Collections.Generic;
class GFG {
static int solve( int [] arr)
{
int n = arr.Length;
int [] left = new int [n];
int [] right = new int [n];
List< int > stack = new List< int >();
for ( int i = 0; i < n; i++) {
int curr = arr[i];
while (stack.Count != 0
&& arr[stack[stack.Count - 1]] >= curr) {
stack.RemoveAt(stack.Count - 1);
}
if (stack.Count == 0)
left[i] = (i + 1) * (arr[i]);
else {
int small_idx = stack[stack.Count - 1];
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.Add(i);
}
stack.Clear();
for ( int i = n - 1; i > -1; i--) {
int curr = arr[i];
while (stack.Count != 0
&& arr[stack[stack.Count - 1]] >= curr) {
stack.RemoveAt(stack.Count - 1);
}
if (stack.Count == 0)
right[i] = (n - i) * (arr[i]);
else {
int small_idx = stack[stack.Count - 1];
right[i] = right[small_idx]
+ (small_idx - i) * (arr[i]);
}
stack.Add(i);
}
int ans = 0;
for ( int i = 0; i < n; i++) {
int curr = left[i] + right[i] - arr[i];
ans = Math.Max(ans, curr);
}
return (ans);
}
public static void Main( string [] args)
{
int [] arr = { 5, 1, 8 };
Console.WriteLine(solve(arr));
}
}
|
Javascript
<script>
function solve(arr) {
let n = arr.length
let left = new Array(n).fill(0)
let right = new Array(n).fill(0)
let stack = []
for (let i = 0; i < n; i++) {
curr = arr[i]
while (stack.length != 0 &&
arr[stack[stack.length - 1]] >= curr) {
stack.pop()
}
if (stack.length == 0)
left[i] = (i + 1) * (arr[i])
else {
small_idx = stack[stack.length - 1]
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i])
}
stack.push(i)
}
stack = []
for (let i = n - 1; i > -1; i--) {
curr = arr[i]
while (stack.length != 0 &&
arr[stack[stack.length - 1]] >= curr) {
stack.pop()
}
if (stack.length == 0)
right[i] = (n - i) * (arr[i])
else {
small_idx = stack[stack.length - 1]
right[i] = right[small_idx]
+ (small_idx - i) * (arr[i])
}
stack.push(i)
}
ans = 0
for (let i = 0; i < n; i++) {
curr = left[i] + right[i] - arr[i]
ans = Math.max(ans, curr)
}
return (ans)
}
arr = [5, 1, 8]
document.write(solve(arr))
</script>
|
Time Complexity: O(N)
Auxiliary Space: O(N)
Share your thoughts in the comments
Please Login to comment...