剑指offer105-107图问题—深度和广度遍历

剑指 Offer II 105. 岛屿的最大面积

给定一个由 0 和 1 组成的非空二维数组 grid ,用来表示海洋岛屿地图。

一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
在这里插入图片描述

广度优先遍历

设置一个访问标记数组
设置一个移动数组 ,vector<vector> dirs{ {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
设置一个访问队列,元素是二维的,因此需要用二维标识每个元素 queue<pair<int, int>> que
一个大的循环让每个节点都进入遍历函数(如果已经被标记就不用进入),遍历函数里面将这个节点加入队列进入循环
1、弹出 2、执行逻辑 3、加入后续节点

大的遍历在这里插入图片描述
移动
在这里插入图片描述
遍历主逻辑
在这里插入图片描述

class Solution {
private:
    // BFS
    int countArea(vector<vector<int>>& grid, vector<vector<int>>& dirs, vector<vector<bool>>& visited, int i, int j) {
        //用一个队列存放元素,由于是二维因此需要两个元素指定坐标
        queue<pair<int, int>> que;
        que.push({ i, j });  
        visited[i][j] = true;

        int area = 0; //存放面积
        while (!que.empty()) {
            auto pos = que.front(); //获取队列头元素后再弹出
            que.pop();
            area++;                 //对元素执行的操作
            //继往开来 加入后续的元素过程
            for (auto& d : dirs) { //对四个方向进行遍历 
                int r = pos.first + d[0];//第一个元素为行移动
                int c = pos.second + d[1];//第二个元素为列移动
                if (r >= 0 && r < grid.size() &&//如果移动后不超左边界,右边界,上边界,下边界
                    c >= 0 && c < grid[0].size() &&//并且没被访问过,而且有元素,那么将其加入队列
                    grid[r][c] == 1 && !visited[r][c]) {
                    que.push({ r, c });
                    visited[r][c] = true;
                }
            }
        }
        return area;
    }

public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        //定义一个已访问数组,初始化全设为0
        vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));
        int maxArea = 0; //记录最大岛屿面积
        //{1, 0}表示向右移动 {-1, 0}表示向左移动  {0, 1}表示向下移动  {0, -1}表示向上移动
        vector<vector<int>> dirs{ {1, 0}, {-1, 0}, {0, 1}, {0, -1} };

        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (grid[i][j] == 1 && !visited[i][j]) {   //如果是1并且没有被访问,那么进入递归
                     //传递这个网格,dirs,已访问名单,当前行,列
                    int area = countArea(grid, dirs, visited, i, j);
                    maxArea = max(area, maxArea); //更新最大岛屿面积
                }
            }
        }
        return maxArea;
    }
};
深度优先遍历

和广度优先差不多,只是把队列换成了栈,
队列先进先出,那么第一个节点出队列,把它的孩子都加上,下一个运行的并不是这些孩子
栈后进先出,那么第一个节点出栈,把它的孩子都加上,下一个运行的就是这些孩子

虽然访问的顺序不一样,但是代码几乎相同

仅仅是将队列换成了栈
在这里插入图片描述

剑指 Offer II 106. 二分图

在这里插入图片描述
在这里插入图片描述

剑指 Offer II 107. 矩阵中的距离

给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        //dists 保存各个格子距离最近的0的位置
        vector<vector<int>> dists(mat.size(), vector<int>(mat[0].size()));
        //访问队列
        queue<pair<int, int>> que;
        //dirs为移动方向
        vector<vector<int>> dirs{ {0, 1}, {0, -1}, {1, 0}, {-1, 0} };

        //遍历这个数组
        for (int i = 0; i < mat.size(); ++i) {
            for (int j = 0; j < mat[0].size(); ++j) {
                //初始化dists,如果数字本身为0,那么距离就是0 否则初始化为无穷大
                if (mat[i][j] == 0) {
                    dists[i][j] = 0;       //dists保存到0的位置,本身为0则设置为0
                    que.push({ i, j });  //将所有本身为0的节点加入到队列中
                }
                else {
                    dists[i][j] = INT_MAX; //dists本身不为0设置为无穷大
                }
            }
        }

        while (!que.empty()) {
            auto pos = que.front();
            que.pop();
            //dist为距离最近0的位置
            int dist = dists[pos.first][pos.second];
            for (auto& d : dirs) {  //对上下左右进行遍历
                int r = pos.first + d[0];
                int c = pos.second + d[1];
                //保证不出界
                if (r >= 0 && r < mat.size() && c >= 0 && c < mat[0].size()) {
                    //对这个元素 上下左右进行判断,只将
                    if (dist + 1 < dists[r][c]) {
                        dists[r][c] = dist + 1;
                        que.push({ r, c });
                    }
                }
            }
        }
        return dists;
    }
};

图遍历总结

在这里插入图片描述

1、广度优先遍历类似层序遍历,它是有层次关系的,在以后涉及图的层序遍历就用广度优先,类似树,但比树更高级的是它可以决定树的根节点可以有多个节点。
深度优先遍历就是针对树进行前中后序遍历

2、一般图是用二维数组来表示,针对图上的点上下左右的移动可以通过

vector<vector<int>> dirs{ {0, 1}, {0, -1}, {1, 0}, {-1, 0} };

for (auto& d : dirs) {  //对上下左右进行遍历
                int r = pos.first + d[0];
                int c = pos.second + d[1];
              判断出界
             if (r >= 0 && r < mat.size() && c >= 0 && c < mat[0].size()) {
                    dists[r][c]就是上下左右的元素
                }          
 }

3、还有个标记访问数组,在传递给函数时要用&来接收

vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));

4、这两个遍历的代码一个样,只是区别在于用得队列还是栈

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贪睡的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值