参考链接:详细通俗的思路分析,多解法
求每一列的水,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。
装水的多少,当然根据木桶效应,我们只需要看左边最高的墙和右边最高的墙中较矮的一个就够了。
解题思路:
- ① 最开始我也想是按行计数->超时;
- ② 按列计数->要找到左右两边最高的柱子,根据(短板高度-当前高度)计算当前列可接的几个单位雨水;
- 2.1 暴力求左右两边最高的柱子,对所有列都左右遍历一遍,复杂度n*n
- 2.2 动态规划,用两个数组maxleft[], maxright[]来记录当前下标的左右最高的柱子,遍历一遍maxleft[i] = max(maxleft[i-1], height[i-1]),同理得右边,复杂度2*n,然后遍历一遍求总的雨水单位min(maxleft[i],maxright[i]) - height[i]
- 2.3 双指针,只需遍历一遍,left=1,right=len()-2(因为最外头的柱子一定没有接到水),
- if height[left-1] < height[right+1](计算索引为left这一列的水),就说明左边最高的柱子比右边最高的柱子矮(听我解释,
- 1.如果右边有比左边这个最高的还矮的柱子,但因为有这个右边高柱子在,按照短板原则,取两边最高里矮的,蓄水还得看左边那个;
- 2.如果右边有比左边这个最高的还高的柱子,那就更加看左边的柱子了(两高取短板))
- else(计算索引为right这一列的水)
- if height[left-1] < height[right+1](计算索引为left这一列的水),就说明左边最高的柱子比右边最高的柱子矮(听我解释,
class Solution:
def trap(self, height: List[int]) -> int:
# ① 最开始我也想是按行计数->超时;② 按列计数->要找到左右两边最高的柱子,根据(短板高度-当前高度)计算当前列可接的几个单位雨水;
# 2.1 暴力求左右两边最高的柱子,对所有列都左右遍历一遍,复杂度n*n
# 2.2 动态规划,用两个数组maxleft[], maxright[]来记录当前下标的左右最高的柱子,遍历一遍maxleft[i] = max(maxleft[i-1], height[i-1]),同理得右边,复杂度2*n,然后遍历一遍求总的雨水单位min(maxleft[i],maxright[i]) - height[i]
# 2.3 双指针,只需遍历一遍,left=1,right=len()-2(因为最外头的柱子一定没有接到水),
# if height[left-1] < height[right+1](计算索引为left这一列的水),就说明左边最高的柱子比右边最高的柱子矮(听我解释,
# 1.如果右边有比左边这个最高的还矮的柱子,但因为有这个右边高柱子在,按照短板原则,取两边最高里矮的,蓄水还得看左边那个;
# 2.如果右边有比左边这个最高的还高的柱子,那就更加看左边的柱子了(两高取短板))
# else(计算索引为right这一列的水)
left, right = 1, len(height) - 2
maxleft, maxright = 0, 0
res = 0
while left <= right:
if height[left-1] < height[right+1]:
maxleft = max(maxleft, height[left-1]) # 短板是左边的最高柱子
res += max(maxleft - height[left], 0) # 计算蓄水量
left += 1
else:
maxright = max(maxright, height[right+1]) # 短板是右边的最高柱子
res += max(maxright - height[right], 0)
right -= 1
return res