今天是冬至日,也是考研第一天
考完试,大家也要记得吃饺子啊!
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路:
这一题我采用的方法有点分而治之的味道,简单来说就是把整个容器所能承接雨水的体积分解为几个符合要求小容器承接雨水的体积,也就是下图所示:
大的思想方针确定了,我们现在所要思考的就是如何找到符合要求的容器,以及该容器所能承接雨水的体积怎么计算,我们一个一个来。
1 找到符合要求的容器
我的方法是可以首先固定一个起始值start(可以理解为构建容器的起始高度)起始值start=height[0],我们接下来要找的就是该小容器的结束高度end。关键时刻到了,很多人就会想:该结束高度end要符合什么要求呢?我给的要求是只要比起始值start大就符合要求。我知道很多笔友看到这儿肯定会想破口大骂:作者你是pig吧,结束高度end谁说非得比起始值start大就行,比它小也是没问题的,就比如下图所示:
此图对应的情况就刚好可以说明问题。因为看上图很容易知道:该容器是可以承接雨水的,但是按照我的思路来,是得不出答案的。那岂不是说我之前说的话在放屁?哈哈哈哈哈,当然不会,我还不是无聊的无的放矢。我的解决方法是:当确定起始值start后,依次遍历start后面的值,如果发现没有一个值比start大,就把start改成start后面的值的最大值,继续遍历。过程如下图所示:
怎么样,是不是觉得我很机灵?啊哈哈哈哈哈,自娱自乐,大家见怪不怪哈
2 计算该容器所能承接雨水的体积
容器找到了,最后一步就是要把雨水体积计算出来了。计算体积其实很简单,具体过程如下图所示:
到了这儿就大功告成了,具体代码如下:
class Solution:
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
if len(height) <= 1:
return 0
# 定义符合要求可以存储雨水的列表集合以及该集合的首元素对应的下标
start = 0
current_height = []
# 定义所能承接雨水的体积
final_volumn = 0
index = 1
# 遍历height数组最后用while循环,方便我们随时回溯,for循环基本上很难回溯
while index < len(height):
# 如果发现当前index下标对应的值比start下标对应的值要大,,这说明[start: index+1]区间的值有可能构成能存储雨水的容器
# 这儿是可能,因为首先[start: index+1]区间长度必须是得大于2的,如果连续两个值相等,则该容器是不能盛水的
if height[index] >= height[start]:
current_height = height[start:index + 1]
final_volumn += self.compute_area(current_height)
print("current_height", current_height)
print("current_area", self.compute_area(current_height))
start = index
# 如果发现当前start下标对应的值比其右边所有元素的都要大,则把当前start下标对应的值改成其右边所有元素的最大值
# 并且index回溯到start位置,继续计算面积
if index == len(height)-1 and start != index:
new_height = height[start+1:]
max_num = max(new_height)
height[start] = max_num
index = start
continue
index += 1
return final_volumn
# 该函数用来计算current_height小块列表中元素对应的面积
# 该current_height小块列表中元素有一点需要注意的是:第一个元素的值一定要比最后一个值小,否则就不符合要求了
# 木板原则,很好理解
def compute_area(self, current_height):
"""
:param current_height: List[int]-->原height数组中需要计算面积的小块列表
:return: current_area: int-->指代给定的current_height小块列表中元素对应的面积
"""
if len(current_height) <= 2:
return 0
# 设定最初的面积为current_height列表中第一个元素与最后一个元素所构建的最大面积
current_area = current_height[0]*(len(current_height)-2)
# 遍历current_height列表中除了首尾元素的剩余元素,依次将相应面积(即该元素对应的值)减去
for index in range(1, len(current_height)-1):
current_area -= current_height[index]
return current_area
if __name__ == "__main__":
height = [0,1,0,2,1,0,1,3,2,1,2,1]
volumn = Solution().trap(height)
print(volumn)
执行效率中等,在50%左右。