去除谷值后最大化给定数组的总和
给定一个大小为N的整数数组arr[] ,任务是在只允许减少元素的值时从数组中移除谷值后最大化数组的总和,即新形成的数组不应包含任何具有修改后价值更大。
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).
例子:
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.
朴素方法:将每个元素视为一个峰值元素,并在峰值元素的两个方向上按降序开始。
If arr = [8, 1, 10, 1, 8 ]
Consider 10 as peak element and then the final array would like [ 1, 1, 10, 1, 1]
时间复杂度:O(N 2 )
辅助空间: O(1)
高效的方法:而不是将每个指标作为一个峰值点。计算每个索引(idx)的前缀和后缀和数组。前缀数组可用于存储从0开始的高度总和。 . . idx满足左侧没有谷点且idx有峰元素的条件。后缀和数组也满足索引idx的后缀的相同条件。
索引处的元素可以向左跨越,直到找到一个较小的元素,假设当前元素是最高的。使用堆栈概念的下一个较小的元素可以在这里使用,只需稍作改动。
请按照以下步骤操作:
- 构建前缀和(左)和后缀和(右)数组。构建数组时会有两种情况。考虑以下前缀和数组的情况。同样适用于后缀和数组。
- 当前元素是迄今为止所有元素中最小的。
所以,留下 [ curr_idx ] = ( i +1 ) * arr[i] 。这里 (i + 1) 表示范围 。 - 左侧有一个带有small_idx的较小元素。
所以, left [ curr_idx] = left[ small_idx ] + (current_idx – small_idx) *arr[i]
使用同样的方法可以计算出右和数组。
- 当前元素是迄今为止所有元素中最小的。
- 现在,遍历每个索引并计算 answer = left[idx] + right[idx] – arr[idx]
注意: arr[idx] 被减去,因为 arr[idx] 被添加到left[]和right[]数组中。
请参阅下图以更好地理解。
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.
下面是上述方法的实现:
C++
// C++ code for the above approach
#include
using namespace std;
// Function to get get the maximum cost
int solve(vector& arr)
{
int n = arr.size();
vector left(n, 0);
vector right(n, 0);
vector stack;
// Calculate left array
for (int i = 0; i < n; i++) {
int curr = arr[i];
while (stack.size() != 0
&& arr[stack[stack.size() - 1]] >= curr) {
stack.pop_back();
}
// Case 1
if (stack.size() == 0)
left[i] = (i + 1) * (arr[i]);
// Case 2
else {
int small_idx = stack[stack.size() - 1];
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.push_back(i);
}
stack.clear();
// Calculate suffix sum array
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);
}
// Driver code
int main()
{
vector arr = { 5, 1, 8 };
cout << solve(arr);
return 0;
}
// This code is contributed by rakeshsahni
Java
// Java code for the above approach
import java.util.*;
class GFG{
// Function to get get the maximum cost
static int solve(int[] arr)
{
int n = arr.length;
int []left = new int[n];
int []right = new int[n];
Vector stack = new Vector();
// Calculate left array
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);
}
// Case 1
if (stack.size() == 0)
left[i] = (i + 1) * (arr[i]);
// Case 2
else {
int small_idx = stack.get(stack.size() - 1);
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.add(i);
}
stack.clear();
// Calculate suffix sum array
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);
}
// Driver code
public static void main(String[] args)
{
int[] arr = { 5, 1, 8 };
System.out.print(solve(arr));
}
}
// This code is contributed by 29AjayKumar.
Python3
# Python code to implement above approach
# Function to get get the maximum cost
def solve(arr):
n = len(arr)
left = [0]*(n)
right = [0]*(n)
stack = []
# Calculate left array
for i in range(n):
curr = arr[i]
while(stack and
arr[stack[-1]] >= curr):
stack.pop()
# Case 1
if (len(stack) == 0):
left[i] = (i + 1)*(arr[i])
# Case 2
else:
small_idx = stack[-1]
left[i] = left[small_idx] \
+ (i - small_idx)*(arr[i])
stack.append(i)
stack.clear()
# Calculate suffix sum array
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)
# Driver code
if __name__ == "__main__":
arr = [5, 1, 8]
print(solve(arr))
C#
// C# code for the above approach
using System;
using System.Collections.Generic;
class GFG {
// Function to get get the maximum cost
static int solve(int[] arr)
{
int n = arr.Length;
int[] left = new int[n];
int[] right = new int[n];
List stack = new List();
// Calculate left array
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);
}
// Case 1
if (stack.Count == 0)
left[i] = (i + 1) * (arr[i]);
// Case 2
else {
int small_idx = stack[stack.Count - 1];
left[i] = left[small_idx]
+ (i - small_idx) * (arr[i]);
}
stack.Add(i);
}
stack.Clear();
// Calculate suffix sum array
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);
}
// Driver code
public static void Main(string[] args)
{
int[] arr = { 5, 1, 8 };
Console.WriteLine(solve(arr));
}
}
// This code is contributed by ukasp.
Javascript
10
时间复杂度:O(N)
辅助空间: 在)