给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。
示例:
给出如下 3x6 的高度图:
[
[1,4,3,1,3,2],
[3,2,1,3,2,4],
[2,3,3,2,3,1]
]
返回 4 。
如上图所示,这是下雨前的高度图[[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] 的状态。
下雨后,雨水将会被存储在这些方块中。总的接雨水量是4。
提示:
1 <= m, n <= 110
0 <= heightMap[i][j] <= 20000
通过次数4,024提交次数9,866
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
可以将降雨理解为雨水从外往里漫进水槽中,那么,设置遍历的优先级,优先从较低的边界开始遍历(但边界的所有方块都需要先进入队列),如果内部存在比最低边界还低的方块,则证明可以积水,能够积水的量即为高度的差值。这么说可能还是难以理解,直接说代码思路:
1. 设置优先级遍历队列,优先遍历队列中最低的方块;
2. 对这个方块向四周进行延伸,排除超出边界和已经入队或者遍历的方块;
3. 如果此时,方块的四周出现高度低于当前方块的情况,则说明可以积水,积水量为差值,累加这个值,之后将这个位置的水填满,再将新的高度加入队列;
4. 循环遍历直到队列为空。
逻辑是这样的,首先把四周的点入队列,取出最小的点进行遍历,此时内部低于这个最小值的点的位置的水,不可能通过四周流出,因此一定可以积水,队列中加上已经遍历的点其实维护的是一个围栏,不断的向内检索低于围栏的点,并把它用水漫进去,遇到高于围栏的点则将它加入围栏,可能在围栏内部会有一圈更高的围栏,而因为更高的围栏会在之后遍历,那么更高的围栏内部的更低的点不会被外部的围栏所影响,这就保证了结果的正确性
注:
1. 方向数组真好用
2. 二维数组的xy和下标对应关系两种情况均可;
3. stl优先级队列的初始化(元素类型,底层实现数据结构,比较结构体),比较结构体是一个结构体,重载了小括号,返回比较的大小,a>b是小顶堆,反之为大顶堆。实例:struct cmp{bool operator()(int &a,int &b)return a>b;};
class Solution {
public:
struct item
{
int x;
int y;
int height;
item(int x,int y,int height):x(x),y(y),height(height){}
};
struct cmp
{
bool operator()(item& a,item &b)
{
return a.height>b.height;
}
};
int trapRainWater(vector<vector<int>>& heightMap) {
//初始化必要数据结构
priority_queue<item,vector<item>,cmp> Q;
int mHeight = heightMap.size();
int mWidth = heightMap[0].size();
//初始化访问数组
//需要三种状态,未加入队列,加入队列,已被访问
vector<vector<int>> visit;
for(auto vec:heightMap)
{
visit.push_back(vector<int>(mWidth,0));
}
//初始化优先级队列
for(int i = 0;i<mWidth;i++)
{
Q.push(item(i,0,heightMap[0][i]));
visit[0][i] = 1;
Q.push(item(i,mHeight-1,heightMap[mHeight-1][i]));
visit[mHeight-1][i] = 1;
}
for(int i = 0;i<mHeight;i++)
{
Q.push(item(0,i,heightMap[i][0]));
visit[i][0] = 1;
Q.push(item(mWidth-1,i,heightMap[i][mWidth-1]));
visit[i][mWidth-1] = 1;
}
//四个方向的方向数组
int dx[] = {1,-1,0,0};
int dy[] = {0,0,1,-1};
int ret = 0;
//深度优先搜索
while(!Q.empty())
{
item cur = Q.top();
int x = cur.x;
int y = cur.y;
int h = cur.height;
Q.pop();
visit[y][x] = 1;
//四个方向遍历
for(int i = 0;i<4;i++)
{
int nx = x+dx[i];
int ny = y+dy[i];
if(nx<0||nx>=mWidth||ny<0||ny>=mHeight||visit[ny][nx]!=0)
{
continue;
}
else
{
int nh = heightMap[ny][nx];
visit[ny][nx] = 1;
//cout<<ny<<"\t"<<nx<<"\t"<<nh<<"\t"<<h<<endl;
if(nh<h)
{
ret+=(h-nh);
nh = h;
}
Q.push(item(nx,ny,nh));
}
}
}
return ret;
}
};