当青训营遇上码上掘金
这是我参加的青训营与码上掘金的创作活动,其中我选择的主题为主题4:攒青豆
分析一下题目:现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
刚看到这个题目以及给出的配套示意图我就有点没绷住,诶呀,这不是我LEETCODE 42:接雨水吗,只能说不愧是字节,在之前早有耳闻字节面试:先来一道简单的——接雨水(不是)
还是来分析一下题目吧,这道题的做法有很多,我选择的是利用单调栈计算攒到的青豆总量。
具体思路是这样的:维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height中的元素递减。从左到右遍历数组,遍历到下标 i 时,如果栈内至少有两个元素,记栈顶元素为top,top的下面一个元素是left,则一定有height[left]>=height[top]。如果height[left]>height[top],则得到一个可以攒青豆的区域,该区域的宽度是i-left-1,高度为min(height[left],height[i])-height[top],根据宽度和高度即可计算得到该区域能攒的青豆量。为了得到left,需要将top 出栈。在对top 计算能攒的青豆量之后,left变成新的 top,重复上述操作,直到栈变为空,或者栈顶下标对应的height中的元素大于或等于height[i]。在对下标 i 处计算能接的雨水量之后,将i入栈,继续遍历后面的下标,计算能攒的青豆量。遍历结束之后即可得到能攒的青豆总量。
最后贴一下代码
def trap(height):
ans = 0
stack = list()
n = len(height)
for i, h in enumerate(height):
while stack and h > height[stack[-1]]:
top = stack.pop()
if not stack:
break
left = stack[-1]
currWidth = i - left - 1
currHeight = min(height[left], height[i]) - height[top]
ans += currWidth * currHeight
stack.append(i)
return ans
if __name__ == '__main__':
height = [4,2,0,3,2,5]
ans = trap(height)