leetcode
leetcode 2651 ~ 2700
接雨水 II

接雨水 II

难度:

标签:

题目描述

Given an m x n integer matrix heightMap representing the height of each unit cell in a 2D elevation map, return the volume of water it can trap after raining.

 

Example 1:

Input: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
Output: 4
Explanation: After the rain, water is trapped between the blocks.
We have two small ponds 1 and 3 units trapped.
The total volume of water trapped is 4.

Example 2:

Input: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]]
Output: 10

 

Constraints:

  • m == heightMap.length
  • n == heightMap[i].length
  • 1 <= m, n <= 200
  • 0 <= heightMap[i][j] <= 2 * 104

代码结果

运行时间: 126 ms, 内存: 18.5 MB


// Java Stream 不适合用来处理这个问题,因为它需要复杂的状态管理和优先级队列的操作。
// 因此,解决这个问题的最有效方式是使用常规的循环和队列,而不是使用Java Streams。

解释

方法:

该题解使用了最小堆来解决接雨水问题。首先将矩阵周边的元素加入最小堆,并初始化水位数组water。然后不断从堆顶取出高度最小的元素,判断其四周是否有未访问过的元素,如果有就计算该位置能接的雨水量,并将其加入最小堆。重复这个过程直到堆为空,最终的接雨水总量就是答案。

时间复杂度:

O(mn * log(mn))

空间复杂度:

O(mn)

代码细节讲解

🦆
为什么在初始化时,只将矩阵的边界元素加入最小堆,而不是全部元素?
在解决接雨水的问题时,水位的最高可能性始于边缘,因为边缘没有其他阻挡可以阻止水流走。通过从边界开始,我们可以确保我们模拟的水流是从最低点开始,逐渐向内部蔓延。这种方法可以避免不必要的计算,并能更准确地反映水的流动和积累。此外,边界元素是确定水能到达的最低高度的关键,它们自然形成了问题的'围栏'。
🦆
在计算可以接的雨水量时,为什么要比较当前元素的高度与水位数组中的水位,而不是直接使用矩阵中的高度?
计算接雨水量时,需要考虑由于四周较高的障碍物可能造成的水位提升。如果仅使用原始矩阵中的高度,我们无法考虑到因周围更高的障碍物而在较低地方积累的水。水位数组中的水位代表了实际的水面高度,包括由于四周的堵塞而可能上升的水位。这种方法确保了每个位置的计算都基于最真实的水面情况,从而准确地模拟和计算积水量。
🦆
在从最小堆中取出元素后,更新四周元素的策略为何选择只更新未访问过的元素?
选择只更新未访问过的元素是为了优化算法的性能并避免重复计算。一旦一个元素的水位被计算并更新,就意味着它已经被考虑过,其水位是当前可能的最小水位。如果重新更新已访问过的元素,可能会导致不必要的重复计算和错误的水位计算。此外,使用最小堆的性质保证了我们总是从最低可能的水位开始扩散,确保整个计算过程的正确性和效率。

相关问题

接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

 

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

 

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105