我的思路:依次计算每一列能接收的雨水量。
关键点:如何计算得到每一列所能接收到的雨水量?
某一列能够接收到的雨水量,取决于其左右两侧最高的柱子。仅有当左右两侧的柱子均高于该列的高度,该列才可收到雨水,其雨水量为 min( left_height-h , right_height-h) 。
class Solution:
def trap(self, height: List[int]) -> int:
# height数组->对象属性
self.height=height
self.height_len=len(height)
# 哈希表存储上一时刻的left_height与right_height
Hash=dict()
Hash['left_height']=0
Hash['right_height']=max(height)
self.Hash=Hash
# rain_sum:总雨水量
rain_sum=0
# 依次计算每一个柱子所能接水的高度
# i为索引
for i in range(len(height)):
# 传入柱子的索引
rain_sum+=self.rain_calculate(i)
return rain_sum
def rain_calculate(self,index):
# 取自身高度h
h=self.height[index]
# 左侧高度
if index:
left_height=max(self.Hash['left_height'],self.height[index-1])
else:
left_height=0
# 右侧高度
if self.height[index]!=self.Hash['right_height']:
right_height=self.Hash['right_height']
else:
if index==self.height_len-1:
right_height=0
else:
seq_temp=self.height[index+1:self.height_len]
right_height=max(seq_temp)
# 更新哈希表
self.Hash['left_height']=left_height
self.Hash['right_height']=right_height
# 仅有当left_height和right_height均高于h时,该列才可接收到雨水
if left_height>h and right_height>h:
return min(left_height-h,right_height-h)
else:
return 0
关键点:哈希表存储上一时刻的left_height与right_height
为什么需要存储上一时刻的left_height与right_height?
数组从左往右遍历,新柱子的 left_height 直接取 max(前一个柱子的left_height , 前一个柱子的高度),有些类似递归的思想。
新柱子的 right_height 则分为两种情况,一种是 新柱子的高度不等于前一个柱子的 right_height,这种情况下则令新柱子的 right_height 直接取 前一个柱子的 right_height 即可;另一种情况则是 新柱子的高度等于前一个柱子的 right_height,即说明前一个柱子的 right_height 可能取自该根柱子,则新柱子的 right_height 取后面的柱子的最大值(数组切片) 即可。
思路2:动态规划
动态规划 - 复杂度分析
时间复杂度为:O(n)
空间复杂度为:O(n)
思路3:单调栈
class Solution:
def trap(self, height: List[int]) -> int:
ans = 0
# 建立单调递减栈,用列表存储
stack = list()
# 从左向右依次遍历
for i, h in enumerate(height):
# 当栈不为空且h大于栈顶的高度时,进入while循环
while stack and h > height[stack[-1]]:
# 取出栈顶元素,作为低洼
top = stack.pop()
# 若取出栈顶元素后栈为空,则跳出while循环
if not stack:
break
# left为左边界的索引,i为右边界的索引
left = stack[-1]
currWidth = i - left - 1
currHeight = min(height[left], height[i]) - height[top]
ans += currWidth * currHeight
# 循环结束后,将i加入栈中
stack.append(i)
return ans
关键点:单调递减栈
考虑到低洼(可接雨水)必须有左右两侧边界,所以用python列表建立单调递减栈。当出现某一根柱子大于栈顶元素的高度时,开始进入内循环。出栈的top为低洼,根据left和right边界索引计算雨水存量,直到下一个栈顶大于等于h,方可跳出内循环。最后一定要将 i 入栈,因为 i 仍可能可以构成某一个低洼的左边界。