3D接雨水——考察知识点

leetcode中的接雨水问题

 

从2D到3D,考察的知识点完全不同:2D中要求掌握双指针算法技巧,3D中要求掌握广度优先搜索算法+优先队列使用技巧

针对这个3D接雨水问题,罗列知识点

BFS:

广度优先搜索算法

breadth first search / broad first search

DFS:

深度优先搜索算法

deep first search

 

数据结构——图的遍历算法,根据访问节点的顺序,分为广度优先搜索BFS和深度优先搜索DFS。

  • 什么是图?一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系。
  • 图的表示:对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图和无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。

 

 

广度优先搜索BFS

// 通常用队列(先进先出,FIFO)实现
// 初始化队列Q
Q={起点s};
标记s为已访问;
while(Q非空){
    取QQ队首元素u;
    u出队;
    if(u==目标状态){
        ...
    }
    所有与u相邻且未被访问的点进入队列;
    标记u为已访问;
}

使用队列保存未被检测的结点。结点按照宽度有限的次序被访问和进出队列。

     --类似于树的按层次遍历的过程

     --广搜例子:你的眼镜掉在地上之后,你趴在地板上找。你总是先摸最接近你的地方,如果没有,再摸远一点的地方……

BFS算法用到了优先级队列,注意队列中元素的比较操作重载!

 

 

深度优先搜索DFS

思想:一直往深处走,直到找到接或者走不下去为止

DFS(dep,...) //dep代表目前DFS的深度 
{ 
    if(找到解||走不下去了) 
    { 
        ... 
        return; 
    } 
    枚举下一种情况,DFS(dep+1,...)
 }

使用栈保存未被检测的结点,结点按照深度优先的次序被访问并以此被压入栈中,并以相反的次序出栈进行新的检测。

     --类似于树的先根遍历

     --深搜例子:走迷宫,你没有办法用分身术来站在每个走过的位置。不撞南墙不回头。

DFS算法用到了递归和回溯。

 

 

实际案例:

BFS在三维接雨水问题中的应用。

问题来源与描述:https://leetcode-cn.com/problems/trapping-rain-water-ii/

辅助理解参考:https://blog.csdn.net/weixin_42054167/article/details/91989108

解法:

struct RainNode {
        int i, j, h;
        RainNode(int ii, int jj, int hh) :i(ii), j(jj), h(hh) {}
        bool operator <(const RainNode& root) const {
            return h>root.h;
        }
    };

    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.empty()) return 0;
        int m = heightMap.size(), n = heightMap[0].size();
        int area = 0, h = 0; //h模拟水池外的海平面上升,m*n矩阵可以看做一个可以蓄水的水池

        // 存放访问过的格子,且每次执行时删除高度最小的格子
        // 存放的过程中,会将当前最小高度的几个格子放在前几个位置(后面的并不按顺序排放)
        priority_queue<RainNode> q; //优先级队列,该队列中是将高度小的放在队首

        vector<vector<bool>> visit(m, vector<bool>(n, false)); //m*n矩阵记录高度块是否被访问过

        // 最外围的高度块是不可能蓄水的,放入优先级队列中,且记录为已被访问过
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i == 0 || i == m - 1 || j == 0 || j == n - 1)
                {
                    q.push(RainNode(i, j, heightMap[i][j]));
                    visit[i][j] = true;
                }
            }
        }

        // 一个点的x和y坐标的四邻域,按照上下左右的顺序排列
        vector<int> x = { 0,0,-1,1 }, y = { -1,1,0,0 };

        while (!q.empty())
        {
            auto f = q.top(); //取出队列q中最小的节点

            // 当前格子的水平面高于海平面,海平面上升
            // 否则,计算海水流进低于海平面的格子
            if (h < f.h)
                h++;
            else
            {
                q.pop(); // 删除队列中最小的节点

                // 当前格子的四个邻域的格子,当坐标不超出水池矩阵范围且没有被访问过时,
                for (int k = 0; k < 4; k++)
                {
                    int i = f.i + x[k], j = f.j + y[k];
                    if (i >= 0 && i < m && j >= 0 && j < n && visit[i][j] == false)
                    {
                        int hh = heightMap[i][j];
                        if (hh < h)
                            area += h - hh;
                        q.push(RainNode(i, j, hh));
                        visit[i][j] = true;
                    }
                }
            }
        }

        return area;
    }


 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值