Leetcode.2866 美丽塔 II

题目链接

Leetcode.2866 美丽塔 II rating : 2072

题目描述

给你一个长度为 n n n 下标从 0 0 0 开始的整数数组 m a x H e i g h t s maxHeights maxHeights

你的任务是在坐标轴上建 n n n 座塔。第 i i i 座塔的下标为 i i i ,高度为 h e i g h t s [ i ] heights[i] heights[i]

如果以下条件满足,我们称这些塔是 美丽 的:

  • 1 ≤ h e i g h t s [ i ] ≤ m a x H e i g h t s [ i ] 1 \leq heights[i] \leq maxHeights[i] 1heights[i]maxHeights[i]
  • h e i g h t s heights heights 是一个 山状 数组。

如果存在下标 i i i 满足以下条件,那么我们称数组 h e i g h t s heights heights 是一个 山状 数组:

  • 对于所有 0 < j ≤ i 0 < j \leq i 0<ji ,都有 h e i g h t s [ j − 1 ] ≤ h e i g h t s [ j ] heights[j - 1] \leq heights[j] heights[j1]heights[j]
  • 对于所有 i ≤ k < n − 1 i \leq k < n - 1 ik<n1 ,都有 h e i g h t s [ k + 1 ] ≤ h e i g h t s [ k ] heights[k + 1] \leq heights[k] heights[k+1]heights[k]

请你返回满足 美丽塔 要求的方案中,高度和的最大值 。

示例 1:

输入:maxHeights = [5,3,4,1,1]
输出:13
解释:和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 0 处。
    13 是所有美丽塔方案中的最大高度和。
示例 2:

输入:maxHeights = [6,5,3,9,2,7]
输出:22
解释: 和最大的美丽塔方案为 heights = [3,3,3,9,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 3 处。
    22 是所有美丽塔方案中的最大高度和。
示例 3:

输入:maxHeights = [3,2,5,5,2,3]
输出:18
解释:和最大的美丽塔方案为 heights = [2,2,5,5,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,最大值在 i = 2 处。
    注意,在这个方案中,i = 3 也是一个峰值。 18 是所有美丽塔方案中的最大高度和。
提示:
  • 1 ≤ n = m a x H e i g h t s ≤ 1 0 5 1 \leq n = maxHeights \leq 10^5 1n=maxHeights105
  • 1 ≤ m a x H e i g h t s [ i ] ≤ 1 0 9 1 \leq maxHeights[i] \leq 10^9 1maxHeights[i]109

解法:单调栈 + 前后缀分解

我们定义 p r e pre pre s u f suf suf

  • 定义 p r e [ i ] pre[i] pre[i] [ 0 , i ] [0 , i] [0,i],以 n u m s [ i ] nums[i] nums[i] 为最大值的 前缀和
  • 定义 s u f [ i ] suf[i] suf[i] [ i , n − 1 ] [i , n - 1] [i,n1],以 n u m s [ i ] nums[i] nums[i] 为最大值的 后缀和

为了便于我们操作,我们将 p r e pre pre s u f suf suf 都偏移一个长度,即 p r e pre pre s u f suf suf 的长度都为 n + 1 n + 1 n+1

举例 :

对于 m a x H e i g h t s = [ 5 , 3 , 4 , 1 , 1 ] maxHeights = [5,3,4,1,1] maxHeights=[5,3,4,1,1],则它的 p r e pre pre s u f suf suf 分别为:

  • p r e = { 0 , 5 , 6 , 11 , 4 , 5 } pre = \{ 0,5,6,11,4,5\} pre={0,5,6,11,4,5}
  • s u f = { 13 , 8 , 6 , 2 , 1 , 0 } suf = \{13,8,6,2,1,0 \} suf={13,8,6,2,1,0}

那么最大的美丽塔高度和为 m a x { p r e [ i ] + s u f [ i ] } ( 0 ≤ i ≤ n ) max\{ pre[i] + suf[i]\} \quad (0 \leq i \leq n) max{pre[i]+suf[i]}(0in)

现在问题的关键在于如何求出 p r e pre pre s u f suf suf

我们可以使用单调栈。

对于 p r e pre pre ,我们使用一个栈 s t k stk stk从小到大的记录元素下标 (从栈底到栈顶)。假设当前遍历到的元素为 m a x H e i g h t s [ i ] maxHeights[i] maxHeights[i],并且栈顶元素 大于等于 当前元素,即 m a x H e i g h t s [ s t k . t o p ( ) ] ≥ m a x H e i g h t s [ i ] maxHeights[stk.top()] \geq maxHeights[i] maxHeights[stk.top()]maxHeights[i],那么我们就要不断地弹出栈顶元素。

上述操作完成之后,要么栈顶元素小于当前元素,即 m a x H e i g h t s [ s t k . t o p ( ) ] < m a x H e i g h t s [ i ] maxHeights[stk.top()] < maxHeights[i] maxHeights[stk.top()]<maxHeights[i]要么此时栈为空

我们就设 j j j 为当前的栈顶元素,即 j = s t k . t o p ( ) j = stk.top() j=stk.top();如果栈为空,就设置 j = − 1 j = -1 j=1

那么此时 ( j , i ] (j,i] (j,i] 这一区间的值都应该是 m a x H e i g h t s [ i ] maxHeights[i] maxHeights[i],总和就是 s u m = ( i − j ) × m a x H e i g h t s [ i ] sum = (i - j) \times maxHeights[i] sum=(ij)×maxHeights[i]

所以此时 p r e [ i ] = s u m + p r e [ j ] pre[i] = sum + pre[j] pre[i]=sum+pre[j]

对于求 s u f suf suf 也是同理。

时间复杂度: O ( n ) O(n) O(n)

C++代码:

using LL = long long;

class Solution {
public:
    long long maximumSumOfHeights(vector<int>& nums) {
        int n = nums.size();
        vector<LL> pre(n + 1) , suf(n + 1);
        stack<int> stk{{-1}};

        for(int i = 0;i < n;i++){
            while(stk.size() > 1 && nums[stk.top()] >= nums[i]){
                stk.pop();
            }
            int j = stk.top();

            pre[i + 1] += (i - j) * 1LL * nums[i];
            pre[i + 1] += pre[j + 1];
            stk.push(i);
        }

        //清空栈
        while(!stk.empty()) stk.pop();

        stk.push(n);

        for(int i = n - 1;i >= 0;i--){
            while(stk.size() > 1 && nums[stk.top()] >= nums[i]){
                stk.pop();
            }
            int j = stk.top();
            suf[i] += (j - i) * 1LL * nums[i];
            suf[i] += suf[j];

            stk.push(i); 
        }

        LL ans = 0;
        for(int i = 0;i <= n;i++){
            ans = max(pre[i] + suf[i] , ans);
        }

        return ans;
    }
};

你可能感兴趣的:(Leetcode,单调栈,前后缀分解)