1. 题号和题目名称
- 接雨水 II
2. 题目叙述
给你一个 m x n
的矩阵表示一个地图的高度图,其中 heightMap[i][j]
表示坐标 (i, j)
处的高度。
请你计算这个地图能接多少体积的雨水。
示例 1:
输入: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
输出: 4
解释: 下雨后,雨水将会被存储在这些方块中。总的接雨水量是 4。
示例 2:
输入: 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]]
输出: 10
3. 模式识别
本题可使用优先队列(最小堆)来解决。核心思路是从地图的边界开始,因为边界上的方块无法积水,将边界上的方块加入优先队列,然后不断从优先队列中取出高度最小的方块,向其相邻的方块扩展,根据相邻方块与当前方块的高度关系来计算积水量。
4. 考点分析
- 优先队列(最小堆):使用优先队列来维护当前可扩展的方块中高度最小的方块。
- 广度优先搜索(BFS):从边界开始向内部扩展,不断更新方块的状态。
- 二维数组操作:对二维矩阵进行遍历和操作。
5. 所有解法
- 优先队列 + BFS 解法:上述提到的核心解法,时间复杂度和空间复杂度相对较优。
- 暴力解法:对于每个方块,计算其四周的最小高度,然后根据该高度和当前方块高度的差值计算积水量,但这种方法时间复杂度较高。
6. 最优解法(优先队列 + BFS)的 C 语言代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义优先队列的节点结构体
typedef struct {
int x, y; // 方块在二维矩阵(高度图)中的坐标,x 表示行,y 表示列
int height; // 该方块的高度
} Node;
// 定义优先队列结构体
typedef struct {
Node *data; // 用于存储节点的数组,动态分配内存
int size; // 当前优先队列中节点的数量
int capacity; // 优先队列的容量,即最多能存储的节点数
} PriorityQueue;
// 交换两个节点
void swap(Node *a, Node *b) {
Node temp = *a; // 临时变量存储节点 a 的值
*a = *b; // 将节点 b 的值赋给节点 a
*b = temp; // 将临时变量的值赋给节点 b,完成交换
}
// 调整堆,使其满足最小堆的性质
// pq: 指向优先队列的指针
// idx: 当前要调整的节点的索引
void heapify(PriorityQueue *pq, int idx) {
int left = 2 * idx + 1; // 计算当前节点的左子节点索引
int right = 2 * idx + 2; // 计算当前节点的右子节点索引
int smallest = idx; // 假设当前节点是最小的
// 如果左子节点存在且其高度小于当前最小节点的高度
if (left < pq->size && pq->data[left].height < pq->data[smallest].height) {
smallest = left; // 更新最小节点为左子节点
}
// 如果右子节点存在且其高度小于当前最小节点的高度
if (right < pq->size && pq->data[right