leetcode.407:接雨水Ⅱ

给你一个 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;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值