440 字
2 分钟
42. 接雨水
42. 接雨水
题目链接: LeetCode 42
题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分)。示例 2:
输入:height = [4,2,0,3,2,5]输出:9解题思路
核心思想
每个位置能接的水量 = min(左侧最高柱, 右侧最高柱) - height[i](若为正才接水)。用双指针:left、right 从两端向中间靠拢。关键在于:当 height[left] < height[right] 时,位置 left 的水量由左侧最高决定(此时右边界已经足够高),因此我们可以放心处理左指针。
算法步骤
left=0, right=n-1, left_max=right_max=0, ans=0。- 更新
left_max = max(left_max, height[left])、right_max = max(right_max, height[right])。 - 若
height[left] < height[right]:说明left处左边界是短板,ans += left_max - height[left],left += 1。 - 否则:处理右侧,
ans += right_max - height[right],right -= 1。 - 重复直到
left >= right,返回ans。
逐步举例
height = [0,1,0,2,1,0,1,3,2,1,2,1]:
| 步骤 | left | right | 处理边 | left_max | right_max | 增量 | ans |
|---|---|---|---|---|---|---|---|
| 1 | 0 | 11 | 左(0<1) | 0 | 1 | 0 | 0 |
| 2 | 1 | 11 | 左(1<1)→右 | 1 | 1 | 0 | 1 |
| 3 | 1 | 10 | 左(1<2) | 1 | 2 | 1-1=0 | 1 |
| 4 | 2 | 10 | 左(0<2) | 1 | 2 | 1-0=1 | 2 |
| … | … | … | … | … | … | … | 6 |
最终 ans = 6。
复杂度分析
- 时间复杂度:O(n),双指针各扫描一次。
- 空间复杂度:O(1)。
代码实现
from typing import List
class Solution: def trap(self, height: List[int]) -> int: left, right = 0, len(height) - 1 left_max = right_max = 0 ans = 0 while left < right: left_max = max(left_max, height[left]) right_max = max(right_max, height[right]) if height[left] < height[right]: ans += left_max - height[left] left += 1 else: ans += right_max - height[right] right -= 1 return ansimport sysfrom pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))import unittest
from solution import Solution
class TestSolution(unittest.TestCase): def test_basic(self): self.assertEqual(Solution().trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]), 6)
def test_flat(self): self.assertEqual(Solution().trap([0, 0, 0, 0]), 0)
def test_high_middle(self): self.assertEqual(Solution().trap([4, 2, 0, 3, 2, 5]), 9)
if __name__ == '__main__': unittest.main()