题目描述:
给定 n
个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
1 | 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] |
示例 2:
1 | 输入:height = [4,2,0,3,2,5] |
提示:
1 | n == height.length |
链接:
https://leetcode-cn.com/problems/trapping-rain-water
题目分析
这道题有点像 Leetcode 11.盛最多水的容器,因此也是考虑用双指针的做法。与那道题不同的是,这里的每个柱子并不是没有厚度的“壁”,而且对于所有的“坑”都会盛上水,而不是只选取其中两个壁之间盛水。但是思路应该是一致的,我们可以从两边往中间搜索。这是因为观察可以发现,每个较低的柱子,只要两边有高于它的柱子,则可以填上水直到和较低的一边柱子平齐。而我们在利用双指针搜索的时候,优先扩展较低的那边,则可以保证未搜索的区域不会影响已搜索区域填水的高度。
具体的算法是,维护两个变量记录左边已搜索区域的最大高度 maxleft
和右边已搜索区域的最大高度 maxright
,而 left
和 right
分别记录当前搜索的左右指针(下标)。如果当前是左边的最大高度 maxleft
较小,则扩展左边,若出现了更高的柱子则更新 maxleft
,较低的柱子则填上雨水直到和 maxleft
平齐,也即更新 water
值;同样的,如果是 maxright
较小,则扩展右边,相应地更新 maxright
或者 water
值。最后两个指针相遇的时候搜索结束,得到结果。
1 | class Solution { |
时间复杂度:$O(n)$,其中 $n$ 是数组大小。两个指针从左右两端开始遍历直到相遇,总共只对数组进行了一层遍历。
空间复杂度:$O(1)$。我们只需要常数个变量进行记录。
官方题解
下面的代码是官方题解中双指针的代码,减少了一次判断,将更新 max 值和 water 值(这里是变量 ans
)整合到了一起。相应的指针相遇条件有所不同(因为我们上面的代码更新完 max 值也对指针进行了移动,因此指向的永远是未搜索的区域,必须两个指针已经重合后错开才算搜索完毕)。
官方题解中还有动态规划和栈等其他解法,也可以提供一定的解决思路,时间复杂度都是一样的 $O(n)$,但是动态规划和栈解法均需要 $O(n)$ 的空间。感兴趣的可以阅读 接雨水 - 力扣官方题解。
1 | class Solution { |