【Leetcode | Python】2865. 美丽塔 I [前后缀分解][单调栈]

文章介绍了如何使用单调栈来解决给定一个山脉数组,计算在每个山顶时,数组左右两侧非递减和非递增部分之和减去山顶高度的最大值。通过构建前缀和后缀单调栈,有效地计算出总和。
摘要由CSDN通过智能技术生成

题目

在这里插入图片描述
在这里插入图片描述

思路

将第 i 个元素作为山顶时,可以将山脉数组分为山顶左右两个部分。

对于山顶左边部分,确保数组为非递减数组;对于山顶右边部分,确保数组为非递增数组。

设山顶左边部分构成的非递减数组元素和的最大值为prefix[i],山顶右边部分构成的非递增数组元素和的最大值为suffix[i],则构成的山脉数组的高度和为prefix[i] + suffix[i] - maxHeight[i]

接下来,任务变成计算单调数组的和最大值,这里可以使用单调栈,单调栈可以保证栈中数据的单调性。

对于山顶左边部分,我们维护一个单调不减的单调栈,根据单调栈可以计算山顶左边部分构成的非递减数组元素和的最大值,原理如下:

第 i 个元素作为山顶时山顶左侧的最大高度和 = 单调栈栈顶元素 j 作为山顶时山顶左侧的最大高度和 + 单调栈栈顶 j 与第 i 个元素之间的距离 * 山顶高度
在这里插入图片描述
如图所示,第 5 个元素作为山顶时,单调栈元素包括第0、2和 3这三个元素,栈顶元素为第 3 个元素。

第 5 个元素作为山顶时山顶左侧的最大高度和 = 第 3 个元素作为山顶时山顶左侧的最大高度和 + 单调栈栈顶与山顶之间的距离(5 - 3 = 2) * 山顶高度

对于山顶右边部分,同理。

代码

```python
class Solution:
    def maximumSumOfHeights(self, maxHeights: List[int]) -> int:
        n = len(maxHeights)
        res = 0
        prefix, suffix = [0] * n, [0] * n  # 前缀单调栈 和 后缀单调栈
        stack1, stack2 = [], []

        for i in range(n):
            # stack1 非空 且 当前元素小于栈顶元素时,不断弹出栈顶元素
            while stack1 and maxHeights[i] < maxHeights[stack1[-1]]:
                stack1.pop()
            if stack1:
                prefix[i] = prefix[stack1[-1]] + (i - stack1[-1]) * maxHeights[i]
            else:
                prefix[i] = (i + 1) * maxHeights[i]
            stack1.append(i)  # 添加栈顶元素

        for i in range(n - 1, -1, -1):
            # stack2 非空 且 当前元素小于栈顶元素时,不断弹出栈顶元素
            while stack2 and maxHeights[i] < maxHeights[stack2[-1]]:
                stack2.pop()
            if stack2:
                suffix[i] = suffix[stack2[-1]] + (stack2[-1] - i) * maxHeights[i]
            else:
                suffix[i] = (n - i) * maxHeights[i]
            stack2.append(i)  # 添加栈顶元素
            res = max(res, prefix[i] + suffix[i] - maxHeights[i])

        return res

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值