题目链接:
https://leetcode-cn.com/problems/trapping-rain-water/
这道题从事例图片上来看就是求蓝色部分的面积,但因为黑色面积是已知的,所以我的第一反应是求蓝色加黑色的面积。那么显然就有两种求面积的方式,一种是一列一列的求,另一种就是一层一层的求嘛。
一列一列的求就是求每个横坐标所对应的水面高度。对于任意一个横坐标其水面高度只可能有两种情况,就是下面红色和绿色圈住的:
绿色这种就是这个坐标的柱子比任意一边的柱子要高(或者等于,要严谨✋)导致水放不上去,红色这种就是这个坐标的柱子比两边的柱子都要低,那么此时其高度就等于左边最高的柱子和右边最高的柱子中较小的那一个。所以只要知道每一个位置其左边最高的高度(height_left)和右边最高的高度(height_right)就可以计算出当前位置的水面高度,其高度就等于max(height, min(height_left, height_right))。我们只要遍历一遍数组,记录每个位置的height_left和height_right就可求得总的面积。那这时间复杂度是O(n),空间复杂度也是O(n)。
另一种就是一层一层的求,如下图所示:
那么我们先看一下怎么求红颜色的这层,显然求矩形面积我们就需要知道其宽和高。那么这层的宽显然是两侧端点的距离差,而高则是两侧端点高度中较小的那个值(height_min)。接下来我们就要求绿色这层的面积,那此时就有一个问题了,绿色这层的两个端点我们怎么确定?仔细观察一下,我们便不难发现绿色这层的两个端点肯定在红色这层端点的内侧,且绿色这层的两个端点的高度要大于之前的height_min。那么我们只要利用双指针同时向内侧寻找比height_min高的点就可以求得绿色这层的面积。这种方法的时间复杂度也是O(n),但是空间复杂度只需要O(1),所以算是更优的解法。
以下是双指针求解该问题的代码
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
start, end = 0, len(height) - 1
cont = 0
tmp = 0
while start < end:
if height[start] < height[end]:
cont -= height[start]
if height[start] > tmp:
cont += (height[start] - tmp)*(end - start + 1)
tmp = height[start]
start += 1
else:
cont -= height[end]
if height[end] > tmp:
cont += (height[end] - tmp)*(end - start + 1)
tmp = height[end]
end -= 1
cont -= tmp
return cont