Skip to main content

407.接雨水 II

标签: heap, breadth-first-search

难度: Hard

通过率: 48.62%

原题链接: https://leetcode.com/problems/trapping-rain-water-ii/description/

题目描述

给定一个 m×nm \times n 的整数矩阵 heightMap 代表2D地形图的每个单元格的高度,返回下雨后它能捕获的水的体积。

解题思路

问题需要找到在地形中能捕获水的区域。一个有效的解决方案是使用广度优先搜索(BFS)并结合最小堆来解决。具体步骤如下:

  1. 初始化:我们需要一个优先队列(最小堆)来处理边界最低部分。首先将地形的四个边界全部放入优先队列中,作为初始边界。

  2. 开始搜索:从优先队列中取出高度最低的单元格,这是我们当前最低的边界。使用这个单元格的高度(当前最小高度)作为水能否留存的判断基准。

  3. 扩大搜索区域:从当前最低的单元格出发,检查其相邻(上下左右)的单元格:

    • 如果邻近的单元格的高度低于当前最小高度,说明可以容纳水,水量是当前最小高度与邻近单元格高度的差,加入水量中。
    • 更新邻近单元格为已访问,并将其添加到优先队列中(其高度默认为边界)。
  4. 重复上述过程,直到优先队列为空。此时所有可能蓄水的区域都已计算。

该方法类似于“墙倒水漫”的思路,在探索空间时,总是跟随最低高的边界扩展计算,当越过坡度时就记录水量。

代码实现

import heapq  # Python的优先队列需要使用heapq库

def trapRainWater(heightMap):
if not heightMap or not heightMap[0]:
return 0

m, n = len(heightMap), len(heightMap[0])
visited = [[False] * n for _ in range(m)] # 判定是否访问过
heap = []

# 把所有边界加入堆中
for i in range(m):
heapq.heappush(heap, (heightMap[i][0], i, 0))
heapq.heappush(heap, (heightMap[i][n-1], i, n-1))
visited[i][0] = visited[i][n-1] = True
for j in range(1, n-1): # 避免角落重复加入
heapq.heappush(heap, (heightMap[0][j], 0, j))
heapq.heappush(heap, (heightMap[m-1][j], m-1, j))
visited[0][j] = visited[m-1][j] = True

result = 0
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] # 上下左右四个方向

# 开始BFS
while heap:
height, x, y = heapq.heappop(heap)
# 检查四个方向
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and not visited[nx][ny]:
visited[nx][ny] = True
# 水量计算,水只能有height那么高
result += max(0, height - heightMap[nx][ny])
# 新单元加入堆
heapq.heappush(heap, (max(heightMap[nx][ny], height), nx, ny))

return result

复杂度分析

时间复杂度:O(mnlog(mn))O(mn\log(mn)),其中mmnn分别为矩阵的行数和列数。我们使用优先队列维护边界,其开销为对所有元素进行排序。

空间复杂度:O(mn)O(mn),用于存储每个位置的访问状态以及优先队列存储的元素。