0042. 接雨水
题目地址(42. 接雨水)
https://leetcode-cn.com/problems/trapping-rain-water/
题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

前置知识
空间换时间
双指针
单调栈
公司
阿里
腾讯
百度
字节
双数组
思路
这是一道雨水收集的问题, 难度为hard. 如图所示,让我们求下过雨之后最多可以积攒多少的水。
如果采用暴力求解的话,思路应该是枚举每一个位置 i 下雨后的积水量,累加记为答案。
伪代码
问题转化为求 h 数组,这里 h[i] 其实等于左右两侧柱子的最大值中的较小值,即 h[i] = Math.min(左边柱子最大值, 右边柱子最大值)
如上图那么 h 为 [0, 1, 1, 2, 2, 2 ,2, 3, 2, 2, 2, 1]
问题的关键在于求解左边柱子最大值和右边柱子最大值, 我们其实可以用两个数组来表示leftMax, rightMax, 以 leftMax 为例,leftMax[i]代表 i 的左侧柱子的最大值,因此我们维护两个数组即可。
关键点解析
建模
h[i] = Math.min(左边柱子最大值, 右边柱子最大值)(h 为下雨之后的水位)
代码
代码支持: JS, Python3, C++:
JS Code:
Python Code:
C++ Code:
复杂度分析
时间复杂度:$O(N)$
空间复杂度:$O(N)$
双指针
这种解法为进阶解法, 大家根据自己的情况进行掌握。
思路
上面代码比较好理解,但是需要额外的 N 的空间。从上面解法可以看出,我们实际上只关心左右两侧较小的那一个,并不需要两者都计算出来。具体来说:
如果 l[i + 1] < r[i] 那么 最终积水的高度由 i 的左侧最大值决定。
如果 l[i + 1] >= r[i] 那么 最终积水的高度由 i 的右侧最大值决定。
因此我们不必维护完整的两个数组,而是可以只进行一次遍历,同时维护左侧最大值和右侧最大值,使用常数变量完成即可。这是一个典型的双指针问题,
具体算法:
维护两个指针 left 和 right,分别指向头尾。
初始化左侧和右侧最高的高度都为 0。
比较 height[left] 和 height[right]
3.1 如果 height[left] < height[right], 那么瓶颈在于 height[left],不需要考虑 height[right]
3.1.1 如果 height[left] < left_max, 则当前格子积水面积为(left_max - height[left]),否则无法积水,即积水面积为 0。也可将逻辑统一为盛水量为 max(0, left_max - height[left])
3.1.2 左指针右移一位。(其实就是左指针的位置的雨水量已经计算完成了,我们移动到下个位置用同样的方法计算)
3.2 否则 瓶颈在于 height[right],不需要考虑 height[left]
3.2.1 如果 height[right] < right_max, 则当前格子积水面积为(right_max - height[left]),否则无法积水,即积水面积为 0。也可将逻辑统一为盛水量为 max(0, right_max - height[right])
3.2.2 右指针右移一位。(其实就是右指针的位置的雨水量已经计算完成了,我们移动到下个位置用同样的方法计算)
代码
代码支持: Python, C++, Go, PHP:
Python Code:
C++ Code:
Go Code:
PHP Code:
复杂度分析
时间复杂度:$O(N)$
空间复杂度:$O(1)$
相关题目
更多题解可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。

最后更新于
这有帮助吗?