Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining.

Note:
Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000.

Example:

Given the following 3x6 height map:
[
[1,4,3,1,3,2],
[3,2,1,3,2,4],
[2,3,3,2,3,1]
] Return 4.


The above image represents the elevation map [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] before the rain.


After the rain, water are trapped between the blocks. The total volume of water trapped is 4.

这道题是之前那道 Trapping Rain Water 的拓展,由 2D 变 3D 了,感觉很叼。但其实解法跟之前的完全不同了,之前那道题由于是二维的,我们可以用双指针来做,而这道三维的,我们需要用 BFS 来做,解法思路很巧妙,下面我们就以题目中的例子来进行分析讲解,多图预警,手机流量党慎入:

首先我们应该能分析出,能装水的底面肯定不能在边界上,因为边界上的点无法封闭,那么所有边界上的点都可以加入 queue,当作 BFS 的启动点,同时我们需要一个二维数组来标记访问过的点,访问过的点我们用红色来表示,那么如下图所示:

我们再想想,怎么样可以成功的装进去水呢,是不是周围的高度都应该比当前的高度高,形成一个凹槽才能装水,而且装水量取决于周围最小的那个高度,有点像木桶原理的感觉,那么为了模拟这种方法,我们采用模拟海平面上升的方法来做,我们维护一个海平面高度 mx,初始化为最小值,从1开始往上升,那么我们 BFS 遍历的时候就需要从高度最小的格子开始遍历,那么我们的 queue 就不能使用普通队列了,而是使用优先级队列,将高度小的放在队首,最先取出,这样我们就可以遍历高度为1的三个格子,用绿色标记出来了,如下图所示:

如上图所示,向周围 BFS 搜索的条件是不能越界,且周围格子未被访问,那么可以看出上面的第一个和最后一个绿格子无法进一步搜索,只有第一行中间那个绿格子可以搜索,其周围有一个灰格子未被访问过,将其加入优先队列 queue 中,然后标记为红色,如下图所示:

那么优先队列 queue 中高度为1的格子遍历完了,此时海平面上升1,变为2,此时我们遍历优先队列 queue 中高度为2的格子,有3个,如下图绿色标记所示:

我们发现这三个绿格子周围的格子均已被访问过了,所以不做任何操作,海平面继续上升,变为3,遍历所有高度为3的格子,如下图绿色标记所示:

由于我们没有特别声明高度相同的格子在优先队列 queue 中的顺序,所以应该是随机的,其实谁先遍历到都一样,对结果没啥影响,我们就假设第一行的两个绿格子先遍历到,那么那么周围各有一个灰格子可以遍历,这两个灰格子比海平面低了,可以存水了,把存水量算出来加入结果 res 中,如下图所示:

上图中这两个遍历到的蓝格子会被加入优先队列 queue 中,由于它们的高度小,所以下一次从优先队列 queue 中取格子时,它们会被优先遍历到,那么左边的那个蓝格子进行BFS搜索,就会遍历到其左边的那个灰格子,由于其高度小于海平面,也可以存水,将存水量算出来加入结果 res 中,如下图所示:

等两个绿格子遍历结束了,它们会被标记为红色,蓝格子遍历会先被标记红色,然后加入优先队列 queue 中,由于其周围格子全变成红色了,所有不会有任何操作,如下图所示:

此时所有的格子都标记为红色了,海平面继续上升,继续遍历完优先队列 queue 中的格子,不过已经不会对结果有任何影响了,因为所有的格子都已经访问过了,此时等循环结束后返回res即可,参见代码如下:

class Solution {
public:
int trapRainWater(vector<vector<int>>& heightMap) {
if (heightMap.empty()) return ;
int m = heightMap.size(), n = heightMap[].size(), res = , mx = INT_MIN;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
vector<vector<bool>> visited(m, vector<bool>(n, false));
vector<vector<int>> dir{{,-},{-,},{,},{,}};
for (int i = ; i < m; ++i) {
for (int j = ; j < n; ++j) {
if (i == || i == m - || j == || j == n - ) {
q.push({heightMap[i][j], i * n + j});
visited[i][j] = true;
}
}
}
while (!q.empty()) {
auto t = q.top(); q.pop();
int h = t.first, r = t.second / n, c = t.second % n;
mx = max(mx, h);
for (int i = ; i < dir.size(); ++i) {
int x = r + dir[i][], y = c + dir[i][];
if (x < || x >= m || y < || y >= n || visited[x][y]) continue;
visited[x][y] = true;
if (heightMap[x][y] < mx) res += mx - heightMap[x][y];
q.push({heightMap[x][y], x * n + y});
}
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/407

类似题目:

Trapping Rain Water

参考资料:

https://leetcode.com/problems/trapping-rain-water-ii/

https://leetcode.com/problems/trapping-rain-water-ii/discuss/89461/Java-solution-using-PriorityQueue

https://leetcode.com/problems/trapping-rain-water-ii/discuss/89476/concise-C%2B%2B-priority_queue-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Trapping Rain Water II 收集雨水之二的更多相关文章

  1. [LeetCode] 407. Trapping Rain Water II 收集雨水之二

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  2. [LeetCode] 407. Trapping Rain Water II 收集雨水 II

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  3. Leetcode: Trapping Rain Water II

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  4. [LeetCode] Trapping Rain Water II 题解

    题意 题目 思路 我一开始想的时候只考虑到一个结点周围的边界的情况,并没有考虑到边界的高度其实影响到所有的结点盛水的高度. 我们可以发现,中间是否能够盛水取决于边界是否足够高于里面的高度,所以这必然是 ...

  5. [LeetCode] Trapping Rain Water 收集雨水

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  6. leetcode 11. Container With Most Water 、42. Trapping Rain Water 、238. Product of Array Except Self 、407. Trapping Rain Water II

    11. Container With Most Water https://www.cnblogs.com/grandyang/p/4455109.html 用双指针向中间滑动,较小的高度就作为当前情 ...

  7. LeetCode: Trapping Rain Water 解题报告

    https://oj.leetcode.com/problems/trapping-rain-water/ Trapping Rain WaterGiven n non-negative intege ...

  8. [Swift]LeetCode407. 接雨水 II | Trapping Rain Water II

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  9. [leetcode]Trapping Rain Water @ Python

    原题地址:https://oj.leetcode.com/problems/trapping-rain-water/ 题意: Given n non-negative integers represe ...

随机推荐

  1. 类型基础---CLR Via C#笔记一

    一.所有类型都是从System.Obejct派生 1.下面两个类型定义是完全一致的: class Employee{ ... } class Employee:System.Object{ ... } ...

  2. DataTable与DTO对象的简易转换类

    在web开发过程中,有时候为了数据传输的方便,比如:后台需要更新前端的ViewModel,此时我们定义一个与前端ViewModel结构一样的DTO对象,从数据层获取数据后,将数据封装成DTO然后序列化 ...

  3. "bower.json 中出现语法错误" 的解决方案之一

    当你用 Visual Studio 2015 Update 3 打开从别处下载的开源项目的时候,如果发现 Bower 提示 "bower.json 中出现语法错误". 请检查一下. ...

  4. ASP.NET Core 导入导出Excel xlsx 文件

    ASP.NET Core 使用EPPlus.Core导入导出Excel xlsx 文件,EPPlus.Core支持Excel 2007/2010 xlsx文件导入导出,可以运行在Windows, Li ...

  5. 8 种提升 ASP.NET Web API 性能的方法

    ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能. 在本文中,我将介绍8项提高 ASP.NET Web ...

  6. Linux下安装Redis

    1. 下载最新版本的Redis源代码: 命令:wget http://download.redis.io/redis-stable.tar.gz 2. 解压并编译 命令:tar xzf redis-s ...

  7. 【Java每日一题】20161227

    package Dec2016; public class Ques1227 { public static void main(String[] args){ } { c = 1; } int c ...

  8. Linux安装jdk

    查看Java的版本命令:java -version 查看java版本的方法是:运行--->cmd,输入java –version.注意: java命令后是有个空格的,-version表示参数而已 ...

  9. 数据结构:堆排序 (python版) 小顶堆实现从大到小排序 | 大顶堆实现从小到大排序

    #!/usr/bin/env python # -*- coding:utf-8 -*- ''' Author: Minion-Xu 小堆序实现从大到小排序,大堆序实现从小到大排序 重点的地方:小堆序 ...

  10. Spring在web应用中获得Bean的方法

    一:使用ApplicationContext获得Bean 首先新建一个类,该类必须实现ApplicationContextAware接口,改接口有一个方法,public void setApplica ...