LeetCode接雨水 动态规划
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
思路:
接雨水问题也是一个经典+高频问题。高频问题都是有技巧和套路的。对于接雨水问题,我们要知道每一处(竖直)可容纳的雨水量,然后将它们相加就是最终结果了。一定要细分开来,否则是很难有效计算的。
如何计算每一竖直上的雨水量呢?首先抛出一个结论:每处(竖直)可容纳的雨水高度取决于左右两边的(比它高的)最高的柱子中,较矮的那个。得到这个值后,减去自身高度,就是这一列的容量。
如果左边没有比自己高的列,则这个高度就是自己的高度。右边同样。
举个例子(参考题目当中的图片):
对于第一列,它的高为1,左边没有比它高的,则它左边的最高长度就是它自己1,它右边的最高高度是3,这一列的容量就是min(1,3)-1=0;
对于第二列,它的高度为0,它左边有比它高的列,高度为1,右边也有很多比它高的列,但我们选最高的那个,高度为3,综合选择两边较矮的那个,得其容量为min(1,3)-0=1;
对于第三列,它自身高度为2,它左边没有比它高的,则它左边的最高长度就是自己2,它右边的最高高度是3,这一列的容量就是min(2,3)-2=0;
我们可以用动态规划的方式,用两个动态规划数组分别记录下每一处位置左边比它高的最高高度,以及右边比它高的最高高度。
这两个数组初始化为0. 动态规划的转移方程也很简单:
记录左边最高高度的数组,从左往右生成,left_h[i]=max(left_h[i-1],height[i])
记录右边最高高度的数组,从右往左生成,right_h[i]=max(right_h[i+1],height[i])
代码:
class Solution(object):
def trap(self, height):
ss=0#总容量
#每处(竖直)可容纳的雨水高度等于左右两边的比它高的柱子中,较矮的那个
# 定义base case即可
lenth = len(height)
left_h=[0]*lenth# left_h[i]表示i位置左边的最大高度
right_h=[0]*lenth#i位置右边的最大高度
#base case
left_h[0]=height[0]#最左边的左边最大高度就是自己 #以使得左右边界处会自己减成0
right_h[-1]=height[-1]#最右边的右边最大高度也是自己
#开始动态规划
#计算左边最高高度的数组
for i in range(1,lenth):
left_h[i]=max(left_h[i-1],height[i])
#计算右边最高高度的数组
for i in range(lenth-2,-1,-1):
right_h[i]=max(right_h[i+1],height[i])
#开始正式计算
for i in range(lenth):
#每一列左右两边的(比自己高的)最大高度,取较小的那个与自身做差
ss+=min(left_h[i],right_h[i])-height[i]
return ss
小结:
注意对左右两边的处理,对于最左边的列,左边的最大高度是自己;对于最右边的列,右边的最大高度是自己。因为很显然它们左边或右边分别没有比自己高的列了,所以相应高度就是自己的高度。
总之这个题就是动态规划当中的经典问题了,要记住的是逐一对每一列求其容量。求容量的方法则是根据动态规划,对左右两边展开来求相应高度。
看懂理解后记住即可,不要钻牛角尖了。因为我不觉得有多少人能第一次看着个题就可以想出这种办法(起码我自己是),所以不要灰心,恭喜你又记住了一个套路,加油!。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了