Python|动态规划解接雨水问题

萝らか妹 提交于 2021-02-14 14:12:21

欢迎点击「算法与编程之美」↑关注我们!

本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列文章。

问题描述

给定n个非负整数表示每个宽度为1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水?

1.1 问题示意图

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

解决方案

首先来理解题意,3能接到水是因为左边最高高度是1右边最高高度是3原本高度是零,可以得到在3的位置能接到水的量是左右最高中最小的减去原本的,然后把所有能接到的水合起来就是答案。

1.普通代码(暴力遍历但超时)

def trap(height):

     ans = 0

     for i in range(len(height)):

         max_left, max_right = 0, 0

         # 寻找 max_left

         for j in range(0, i):

            max_left = max(max_left,  height[j])

         # 寻找 max_right

         for j in range(i, len(height)):

            max_right = max(max_right,  height[j])

         if min(max_left, max_right) > height[i]:

            ans += min(max_left, max_right) -  height[i]

 

     return ans

height=[0,1,0,2,1,0,1,3,2,1,2,1]

print(trap(height))

2.动态规划代码

上述题意符合动态规划的3要素优子结构、边界和状态转移,而且在寻找每个下标的左边和右边最高的柱子时,会对柱子进行反复搜索导致复杂度降低,假如使用两个数组lmaxrmaxlmax[i]表示下标i左边最高柱子的高度,rmax[i] 表示下标i右边最高柱子的高度,很明显,只需要一趟遍历就可以得到结果。这样由于避免了重复计算,就避免了超时。

def trap(height):

     #边界条件

     if len(height)<3:

         return 0

     n=len(height)

     lmax=[0]*n

     rmax=[0]*n

     ans=0

     #初始化左右峰

     lmax[0]=height[0]

     rmax[n-1]=height[n-1]

     #储存左右峰

     for i in range(1,n):

         lmax[i]=max(height[i],lmax[i-1])

     for j in range(n-2,-1,-1):

         rmax[j]=max(height[j],rmax[j+1])

     #遍历 比较每个位置可以存多少水

     for k in range(n):

         if min(rmax[k],lmax[k])>height[k]:

             ans+=min(rmax[k],lmax[k])-height[k]

     return ans

height=[0,1,0,2,1,0,1,3,2,1,2,1]

print(trap(height))


结语

综上所述,只要具备以上三要素的问题均可以采用动态规划的策略进行求解,动态规划可以有效的减少代码的时间复杂度提高代码可读性,是我们编程的好帮手,要熟练掌握。

 

 




END


编  辑   |   王楠岚

责  编   |   王自强


 where2go 团队


   

微信号:算法与编程之美          

长按识别二维码关注我们!

温馨提示:点击页面右下角“写留言”发表评论,期待您的参与!期待您的转发!



本文分享自微信公众号 - 算法与编程之美(algo_coding)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!