题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
法一:动态规划
主要思想: 提前储存所有左边位置的最大值和右边位置的最大值
def trap(self, height: List[int]) -> int:
# 初始化
ans = 0
left_max = [0] * len(height) # dp数组
right_max = [0] * len(height) # dp数组
# 状态转移
# update left_max
for i in range(len(height)):
if i == 0: # 第一个元素
left_max[i] = height[i]
else:
left_max[i] = max(left_max[i-1], height[i])
# update right_max
for j in range(len(height)-1, -1, -1):
if j == len(height)-1: # 最后一个元素
right_max[j] = height[j]
else:
right_max[j] = max(right_max[j+1], height[j])
# update ans
for i in range(len(height)):
ans+= min(left_max[i],right_max[i]) - height[i]
return ans
法二:单调栈
主要思想: 积水只能在低洼处形成,当后面的柱子高度比前面的低,是无法接雨水的。所以用单调栈储存可能储存的柱子,当找到一根比前面高的柱子,就可以接到雨水。
def trap(self, height: List[int]) -> int:
from collections import deque
ans = 0
st = deque(maxlen=len(height)) # 使用collections.deque实现栈
right_idx = 0 # 记录索引
while right_idx < len(height):
while st and height[st[-1]]<height[right_idx]:
curr_idx = st.pop()
if not st: # 判断是否已空
break
intv = right_idx - st[-1] - 1
height_diff = min(height[st[-1]], height[right_idx]) - height[curr_idx]
ans += intv * height_diff # 增量累计
# 更新索引
st.append(right_idx)
right_idx+=1
return ans
法三:双指针
def trap(self, height: List[int]) -> int:
# 初始化
ans = 0
left, right = 0, len(height) - 1
left_max, right_max = 0, 0
# 移动左右指针
while left < right:
# 分成两端
if height[left] < height[right]:
if left_max < height[left]:
left_max = height[left]
else:
ans += left_max - height[left]
left+=1
else:
if right_max < height[right]:
right_max = height[right]
else:
ans += right_max - height[right]
right-=1
return ans