LeetCode 接雨水II(优先队列+广度优先搜索BFS)

给定一个 m x n 的矩阵,其中的值均为正整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。
说明:
m 和 n 都是小于110的整数。每一个单位的高度都大于0 且小于 20000。

示例:

给出如下 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。
思路分析:刚开始拿到这道题,一脸懵逼,感觉二维平面的处理比一维线性的处理困难太多了。(下面代码是从评论区翻出来的)
首先我们需要明白,在给的高度图中的四个边界上不可能积水。(最上行、最下行、最左、最右列)
我们构造一个优先队列(维持从小到大的排序顺序(小顶堆)),起始我们将四个边界的点全部放入队列(并标记访问),然后使用广度优先搜索法,一直取出队头,如果遇到了比自己高的且没有访问过的点(上下左右四个方向),放入队列(标记访问),如果比自己低,则填充雨水,并更新原始地图。直到队列为空。

struct Qitem{
    int x;
    int y;
    int h;
    Qitem(int _x,int _y,int _h):x(_x),y(_y),h(_h){}
};
 
struct cmp{
    bool operator()(const Qitem& a,const Qitem &b){
        return a.h>b.h;
    }
};
 
class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        priority_queue<Qitem,vector<Qitem>,cmp> Q;//小顶堆
        //行数或列数小于3,则无法积水
        if(heightMap.size() < 3|| heightMap[0].size() < 3){
            return 0;
        }
        int row = heightMap.size();
        int col = heightMap[0].size();
        vector<vector<int>> Mark(heightMap.size(),vector<int>(heightMap[0].size()));//mark[x][y]用于标记heightMap[x][y]是否访问过
        //将四周的点添加至优先级队列,并做标记Mark
        for(int i = 0 ; i <row ; i++){
            Q.push(Qitem(i,0,heightMap[i][0]));
            Mark[i][0] = 1 ;
            Q.push(Qitem(i,col - 1 ,heightMap[i][col - 1]));
            Mark[i][col - 1 ] = 1 ;
        }
        for(int j = 1 ; j <col - 1 ; j++){
            Q.push(Qitem(0,j,heightMap[0][j]));
            Mark[0][j] = 1 ;
            Q.push(Qitem(row - 1 ,j,heightMap[row - 1][j]));
            Mark[row - 1][j] = 1 ;
        }
        
        //扩展的方向数组(上、下、右、左)四个移动方向
        static const int dx[] = {-1,1,0,0};
        static const int dy[] = {0,0,1,-1};
        //最终积水量
        int result = 0;
        //广度优先遍历
        while(!Q.empty()){
            //获取队头信息
            int x = Q.top().x;
            int y = Q.top().y;
            int h = Q.top().h;
            Q.pop();
            //向四个方向扩展
            for(int i = 0 ; i < 4 ;i++){
                int newx = x + dx[i];
                int newy = y + dy[i];
                //如果点超出边界或者已经被标记过,则不会进入队列
                if(newx < 0 || newx >= row 
                        || newy < 0 || newy >=col  
                        || Mark[newx][newy]){
                    continue;
                }
                //当前点的高度高于拓展点时,此时需要填充雨水,
                if(h >heightMap[newx][newy] ){
                    result += h - heightMap[newx][newy];
                    heightMap[newx][newy] = h;//更新原始地图
                }
                //放入队列,标记访问
                Q.push(Qitem(newx,newy,heightMap[newx][newy]));
                 Mark[newx][newy] = 1 ;
            }
        }
        return result;
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/88716582