2865. 美丽塔 I

1.题目介绍

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。
你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。

如果以下条件满足,我们称这些塔是 美丽 的:
1 <= heights[i] <= maxHeights[i]
heights 是一个 山脉 数组。
如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山脉 数组:
-对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
-对于所有 i <= k < n - 1 ,都有 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 == maxHeights <= 103
1 <= maxHeights[i] <= 109

2.题解

2.1 暴力枚举

思路

只要弄懂题目的意思,知道所谓美丽塔,就是选中某一个i作为最高点,向两边逐渐递减降低即可知道如何枚举
类似:

所以枚举所有点作为最高点的情况,从最高点开始,向左向右,要么是小于记录值,保留自身,更新记录值;要么大于记录值,大小改变为记录值,求和。
取其中最大的情况。

代码

class Solution {
public:
    long long maximumSumOfHeights(vector<int>& maxHeights) {
        int n = maxHeights.size();
        long long ans = 0;
        for(int i = 0; i < n; i++){
            int temp = maxHeights[i];
            long long sum = temp;
            for(int j = i - 1; j >= 0; j--){
                sum += min(temp, maxHeights[j]);
                temp = min(temp, maxHeights[j]);
            }
            temp = maxHeights[i];
            for(int k = i + 1; k < n; k++){
                sum += min(temp, maxHeights[k]);
                temp = min(temp, maxHeights[k]);
            }
            ans = max(sum, ans);
        }
        return ans;
    }
};

复杂度分析

时间复杂度:O(n^2),其中 n 表示给定数组的长度。枚举山状数组的最大值需要的时间为 O(n),给定最大值求数组元素的和需要的时间为 O(n)
空间复杂度:O(1)。

2.2 单调栈

思路

大概思路类似如下图,这里的单调栈存的是对应的索引值而不是具体的数组值,如果遇到当前值小于栈中索引对应数组值,则不断出栈,直到单调为止
这里同时记录了所有情况的最大和,prefix(i)表示的是从0到顶峰i(也就是左端单调的最大和),suffix(i)表示的是从顶峰i到n-1(也就是右端单调的最大和)
最终和为prefix(i) + suffix(i) - maxHeights[i] 重复加了一次。
枚举不同的i值,最终取得其中的最大值。

这里我们可以通过类似前缀和的思路,利用之前算得的单调栈头部索引对应的最大和 与 单调栈头部索引到当前索引距离*当前数组值(这些存在着大于当前数组值的情况,所以被事先出栈,一律计算为当前数组值)

代码

class Solution {
public:
    long long maximumSumOfHeights(vector<int>& maxHeights) {
        int n = maxHeights.size();
        long long ans = 0;
        vector<long long> prefix(n), suffix(n);
        stack<int> stk1, stk2;

        for(int i = 0; i < n; i++){
            while(!stk1.empty() && maxHeights[i] < maxHeights[stk1.top()]){
                stk1.pop();
            }
            if(stk1.empty()) prefix[i] = (long long)(i - 0 + 1) * maxHeights[i]; //种树问题,总数等于差值+1
            else{
                prefix[i] = prefix[stk1.top()] + (long long)(i - stk1.top()) * maxHeights[i]; //这里不计算stk1.top()那个索引对应值,所以不加1
            }
            stk1.emplace(i);
        }

        for(int i = n - 1; i >= 0; i--){
            while(!stk2.empty() && maxHeights[i] < maxHeights[stk2.top()]){
                stk2.pop();
            }
            if(stk2.empty()) suffix[i] = (long long)(n - 1 - i + 1) * maxHeights[i];
            else{
                suffix[i] = suffix[stk2.top()] + (long long)(stk2.top() - i) * maxHeights[i];
            }
            stk2.emplace(i);
            ans = max(ans, prefix[i] + suffix[i] - maxHeights[i]);
        }
        return ans;
    }
};
posted @   DawnTraveler  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示