给你一个长度为 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] 。
如果以下条件满足,我们称这些塔是 美丽 的:
如果存在下标 i i i 满足以下条件,那么我们称数组 h e i g h t s heights heights 是一个 山脉 数组:
请你返回满足 美丽塔 要求的方案中,高度和的最大值
输入: 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]
输出:13
解释:和最大的美丽塔方案为 h e i g h t s = [ 5 , 3 , 3 , 1 , 1 ] heights = [5,3,3,1,1] heights=[5,3,3,1,1] ,这是一个美丽塔方案
因为:
- 1 < = h e i g h t s [ i ] < = m a x H e i g h t s [ i ] 1 <=heights[i] <= maxHeights[i] 1<=heights[i]<=maxHeights[i]
- h e i g h t s heights heights 是个山脉数组,峰值在 i = 0 i = 0 i=0 处 。
则有:13是所有美丽塔方案中的最大高度和。
输入: m a x H e i g h t s = [ 6 , 5 , 3 , 9 , 2 , 7 ] maxHeights = [6,5,3,9,2,7] maxHeights=[6,5,3,9,2,7]
输出:22
解释: 和最大的美丽塔方案为 h e i g h t s = [ 3 , 3 , 3 , 9 , 2 , 2 ] heights =[3,3,3,9,2,2] heights=[3,3,3,9,2,2] ,这是一个美丽塔方案
因为:
- 1 < = h e i g h t s [ i ] < = m a x H e i g h t s [ i ] 1 <= heights[i] <= maxHeights[i] 1<=heights[i]<=maxHeights[i]
- h e i g h t s heights heights 是个山脉数组,峰值在 i = 3 i = 3 i=3 处。
则有:22 是所有美丽塔方案中的最大高度和。
输入:$maxHeights = [3,2,5,5,2,3] $
输出:18
解释:和最大的美丽塔方案为 h e i g h t s = [ 2 , 2 , 5 , 5 , 2 , 2 ] heights =[2,2,5,5,2,2] heights=[2,2,5,5,2,2] ,这是一个美丽塔方案
因为:
- 1 < = h e i g h t s [ i ] < = m a x H e i g h t s [ i ] 1 <= heights[i] <= maxHeights[i] 1<=heights[i]<=maxHeights[i]
- h e i g h t s heights heights 是个山脉数组,最大值在 i = 2 i = 2 i=2 处。
注意,在这个方案中,i = 3 也是一个峰值。
18 是所有美丽塔方案中的最大高度和。
提示:
题目类型: 栈、数组、单调栈
Leetcode定级为中等难度,标准的做法,对我来说却难的飞起。做题做的太少咯。
下面我们看题目解析。
根据题意可以知道,假设数组的长度为 n n n,对于山状数组 h e i g h t s heights heights
定义如下:
题目给定了山状数组数组中每个元素的上限,即 h e i g h t s [ i ] ≤ m a x H e i g h t s [ i ] heights[i]≤maxHeights[i] heights[i]≤maxHeights[i],题目要求返回的山状数组所有元素之和的最大值。根据以上分析可知:
暴力法:
根据以上分析,我们依次枚举以 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 [ i ] maxHeights[i] maxHeights[i]为山顶,在内层循环中分别求出 i i i 的左侧元素与右侧的元素,即可求出所有元素之和,此时需要的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
请看我的暴力代码:(773 / 785 个通过的测试用例,会超时!!!)
class Solution(object):
def maximumSumOfHeights(self, maxHeights):
"""
:type maxHeights: List[int]
:rtype: int
"""
lens = len(maxHeights)
heights = [0] * lens
maxiume = 0
for i in range(lens):
n = i - 1
heights[i] = maxHeights[i]
while n >= 0: # 先处理左边递增
heights[n] = min(heights[n + 1], maxHeights[n])
n = n-1
n = i + 1
while n < lens: # 再处理右边递减
heights[n] = min(heights[n - 1], maxHeights[n])
n = n + 1
maxiume = max(sum(heights), maxiume)
heights = [0] * lens
return maxiume
按照题目给定的数量级会存在超时,需要进一步优化。
我只会简单的方法了,现在向大家介绍一下大佬们的想法思路。
动态规划 + 单调栈:
我们定义 f [ i ] f[i] f[i] 表示前 i + 1 i+1 i+1 座塔中,以最后一座塔作为最高塔的美丽塔方案的高度和。我们可以得到如下的状态转移方程:
f [ i ] = { f [ i − 1 ] + heights [ i ] , if heights [ i ] ≥ heights [ i − 1 ] heights [ i ] × ( i − j ) + f [ j ] , if heights [ i ] < heights [ i − 1 ] f[i]=\left\{\begin{array}{ll}f[i-1]+\text { heights }[i], & \text { if heights }[i] \geq \text { heights }[i-1] \\\text { heights }[i] \times(i-j)+f[j], & \text { if heights }[i]<\text { heights }[i-1]\end{array}\right. f[i]={f[i−1]+ heights [i], heights [i]×(i−j)+f[j], if heights [i]≥ heights [i−1] if heights [i]< heights [i−1]
其中 j j j 是最后一座塔左边第一个高度小于等于 h e i g h t s [ i ] heights[i] heights[i]的塔的下标。我们可以使用单调栈来维护这个下标。至于什么是单调栈,不懂得小伙伴可以去其他博客上学习学习,我在这里就不一一赘述了。
我们可以使用类似的方法求出 g [ i ] g[i] g[i],表示从右往左,以第 iii 座塔作为最高塔的美丽塔方案的高度和。最终答案即为 f [ i ] + g [ i ] − h e i g h t s [ i ] f[i]+g[i]−heights[i] f[i]+g[i]−heights[i] 的最大值。
Ok,下面请看代码:
class Solution:
def maximumSumOfHeights(self, maxHeights: List[int]) -> int:
n = len(maxHeights)
stk = []
left = [-1] * n
for i, x in enumerate(maxHeights):
while stk and maxHeights[stk[-1]] > x:
stk.pop()
if stk:
left[i] = stk[-1]
stk.append(i)
stk = []
right = [n] * n
for i in range(n - 1, -1, -1):
x = maxHeights[i]
while stk and maxHeights[stk[-1]] >= x:
stk.pop()
if stk:
right[i] = stk[-1]
stk.append(i)
f = [0] * n
for i, x in enumerate(maxHeights):
if i and x >= maxHeights[i - 1]:
f[i] = f[i - 1] + x
else:
j = left[i]
f[i] = x * (i - j) + (f[j] if j != -1 else 0)
g = [0] * n
for i in range(n - 1, -1, -1):
if i < n - 1 and maxHeights[i] >= maxHeights[i + 1]:
g[i] = g[i + 1] + maxHeights[i]
else:
j = right[i]
g[i] = maxHeights[i] * (j - i) + (g[j] if j != n else 0)
return max(a + b - c for a, b, c in zip(f, g, maxHeights))