|
| 1 | +## 题目地址(2866. 美丽塔 II) |
| 2 | + |
| 3 | +https://leetcode.cn/problems/beautiful-towers-ii/description/ |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。 |
| 9 | +
|
| 10 | +你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。 |
| 11 | +
|
| 12 | +如果以下条件满足,我们称这些塔是 美丽 的: |
| 13 | +
|
| 14 | +1 <= heights[i] <= maxHeights[i] |
| 15 | +heights 是一个 山状 数组。 |
| 16 | +如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组: |
| 17 | +
|
| 18 | +对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j] |
| 19 | +对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k] |
| 20 | +请你返回满足 美丽塔 要求的方案中,高度和的最大值 。 |
| 21 | +
|
| 22 | + |
| 23 | +
|
| 24 | +示例 1: |
| 25 | +
|
| 26 | +输入:maxHeights = [5,3,4,1,1] |
| 27 | +输出:13 |
| 28 | +解释:和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为: |
| 29 | +- 1 <= heights[i] <= maxHeights[i] |
| 30 | +- heights 是个山状数组,峰值在 i = 0 处。 |
| 31 | +13 是所有美丽塔方案中的最大高度和。 |
| 32 | +示例 2: |
| 33 | +
|
| 34 | +输入:maxHeights = [6,5,3,9,2,7] |
| 35 | +输出:22 |
| 36 | +解释: 和最大的美丽塔方案为 heights = [3,3,3,9,2,2] ,这是一个美丽塔方案,因为: |
| 37 | +- 1 <= heights[i] <= maxHeights[i] |
| 38 | +- heights 是个山状数组,峰值在 i = 3 处。 |
| 39 | +22 是所有美丽塔方案中的最大高度和。 |
| 40 | +示例 3: |
| 41 | +
|
| 42 | +输入:maxHeights = [3,2,5,5,2,3] |
| 43 | +输出:18 |
| 44 | +解释:和最大的美丽塔方案为 heights = [2,2,5,5,2,2] ,这是一个美丽塔方案,因为: |
| 45 | +- 1 <= heights[i] <= maxHeights[i] |
| 46 | +- heights 是个山状数组,最大值在 i = 2 处。 |
| 47 | +注意,在这个方案中,i = 3 也是一个峰值。 |
| 48 | +18 是所有美丽塔方案中的最大高度和。 |
| 49 | + |
| 50 | +
|
| 51 | +提示: |
| 52 | +
|
| 53 | +1 <= n == maxHeights <= 105 |
| 54 | +1 <= maxHeights[i] <= 109 |
| 55 | +``` |
| 56 | + |
| 57 | +## 前置知识 |
| 58 | + |
| 59 | +- 动态规划 |
| 60 | +- 单调栈 |
| 61 | + |
| 62 | +## 思路 |
| 63 | + |
| 64 | +这是一个为数不多的 2000 多分的中等题,难度在中等中偏大。 |
| 65 | + |
| 66 | +枚举 i 作为顶峰,其取值贪心的取 maxHeight[i]。关键是左右两侧如何取。由于左右两侧逻辑没有本质区别, 不妨仅考虑左边,然后套用同样的方法处理右边。 |
| 67 | + |
| 68 | +定义 f[i] 表示 i 为峰顶,左侧高度和最大值。我们可以递推地计算出所有 f[i] 的值。同理 g[i] 表示 i 为峰顶,右侧高度和最大值。 |
| 69 | + |
| 70 | +当 f 和 g 都已经处理好了,那么枚举 f[i] + g[i] - maxHeight[i] 的最大值即可。之所以减去 maxHeight[i] 是因为 f[i] 和 g[i] 都加上了当前位置的高度 maxHeight[i],重复了。 |
| 71 | + |
| 72 | +那么现在剩下如何计算 f 数组,也就是递推公式是什么。 |
| 73 | + |
| 74 | +我们用一个单调栈维护处理过的位置,对于当前位置 i,假设其左侧第一个小于它的位置是 l,那么 [l + 1, i] 都是大于等于 maxHeight[i] 的, 都可以且最多取到 maxHeight[i]。可以得到递推公式 f[i] = f[l] + (i - l) * maxHeight[i] |
| 75 | + |
| 76 | + |
| 77 | +## 代码 |
| 78 | + |
| 79 | +- 语言支持:Python3 |
| 80 | + |
| 81 | +Python3 Code: |
| 82 | + |
| 83 | +```python |
| 84 | +class Solution: |
| 85 | + def maximumSumOfHeights(self, maxHeight: List[int]) -> int: |
| 86 | + # 枚举 i 作为顶峰,其取值贪心的取 maxHeight[i] |
| 87 | + # 其左侧第一个小于它的位置 l,[l + 1, i] 都可以且最多取到 maxHeight[i] |
| 88 | + n = len(maxHeight) |
| 89 | + f = [-1] * n # f[i] 表示 i 为峰顶,左侧高度和最大值 |
| 90 | + g = [-1] * n # g[i] 表示 i 为峰顶,右侧高度和最大值 |
| 91 | + def cal(f): |
| 92 | + st = [] |
| 93 | + for i in range(len(maxHeight)): |
| 94 | + while st and maxHeight[i] < maxHeight[st[-1]]: |
| 95 | + st.pop() |
| 96 | + # 其左侧第一个小于它的位置 l,[l + 1, i] 都可以且最多取到 maxHeight[i] |
| 97 | + if st: |
| 98 | + f[i] = (i - st[-1]) * maxHeight[i] + f[st[-1]] |
| 99 | + else: |
| 100 | + f[i] = maxHeight[i] * (i + 1) |
| 101 | + st.append(i) |
| 102 | + cal(f) |
| 103 | + maxHeight = maxHeight[::-1] |
| 104 | + cal(g) |
| 105 | + maxHeight = maxHeight[::-1] |
| 106 | + ans = 0 |
| 107 | + for i in range(len(maxHeight)): |
| 108 | + ans = max(ans, f[i] + g[n - 1 - i] - maxHeight[i]) |
| 109 | + return ans |
| 110 | +``` |
| 111 | + |
| 112 | + |
| 113 | +**复杂度分析** |
| 114 | + |
| 115 | +令 n 为数组长度 |
| 116 | + |
| 117 | +- 时间复杂度:$O(n)$ |
| 118 | +- 空间复杂度:$O(n)$ |
| 119 | + |
| 120 | +f 和 g 以及 st 都使用 n 的空间。并且我们仅遍历了 maxHeights 数组三次,因此时间和空间复杂度都是 n。 |
| 121 | + |
0 commit comments