📌  相关文章
📜  去除谷值后最大化给定数组的总和

📅  最后修改于: 2022-05-13 01:56:07.863000             🧑  作者: Mango

去除谷值后最大化给定数组的总和

给定一个大小为N的整数数组arr[] ,任务是在只允许减少元素的值时从数组中移除谷值后最大化数组的总和,即新形成的数组不应包含任何具有修改后价值更大。

例子

朴素方法:将每个元素视为一个峰值元素,并在峰值元素的两个方向上按降序开始。

时间复杂度:O(N 2 )
辅助空间 O(1)

高效的方法:而不是将每个指标作为一个峰值点。计算每个索引(idx)的前缀和后缀和数组。前缀数组可用于存储从0开始的高度总和. . idx满足左侧没有谷点且idx有峰元素的条件。后缀和数组也满足索引idx的后缀的相同条件。

索引处的元素可以向左跨越,直到找到一个较小的元素,假设当前元素是最高的。使用堆栈概念的下一个较小的元素可以在这里使用,只需稍作改动。

请按照以下步骤操作:

  • 构建前缀和(左)和后缀和(右)数组。构建数组时会有两种情况。考虑以下前缀和数组的情况。同样适用于后缀和数组。
    1. 当前元素是迄今为止所有元素中最小的。
      所以,留下 [ curr_idx ] = ( i +1 ) * arr[i] 。这里 (i + 1) 表示范围 。
    2. 左侧有一个带有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[]数组中。

请参阅下图以更好地理解。

下面是上述方法的实现:

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)
辅助空间 在)