我爱学算法之—— BFS之FLoodFill算法

前言

FloodFill是一直从指定起点出发,通过递归/迭代遍历相邻且满足条件的算法。

核心原理

  • 以起始位置为中心,向上下左右等相邻方向扩散。
  • 只遍历与起始点相邻且满足条件的元素,遇到边界(属性不同)则停止。

这里使用BFS算法,来解决这类问题。

BFS也就是广度优先遍历,代码实现通常要使用队列结构,类似与层序遍历的操作。

一、图像渲染

题目解析

这道题给定一个n*m的二维数组,以及起点坐标(sr,sc),以及要修改的颜色color,我们要从(sr,sc)开始对其相邻(上、下、左、右)且与该位置颜色相同(对应位置的值相等)进行染色。

最后返回染色号的数组。

算法思路

这道题还是非常简单的,我们只需要从(sr,sc)开始,进行一次BFS,在遍历的过程中进行染色即可。

这道题也可以使用DFS、递归遍历来解决。

代码实现

cpp 复制代码
class Solution {
public:
    typedef pair<int, int> PII;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc,
                                  int color) {
        int prev = image[sr][sc];
        if (prev == color)
            return image;
        int n = image.size();
        int m = image[0].size();
        queue<PII> pq;

        pq.push({sr, sc});
        while (pq.size() > 0) {
            auto [x, y] = pq.front();
            pq.pop();
            image[x][y] = color;
            for (int i = 0; i < 4; i++) {
                int a = x + dx[i];
                int b = y + dy[i];
                if (a >= 0 && a < n && b >= 0 && b < m && image[a][b] == prev)
                    pq.push({a, b});
            }
        }
        return image;
    }
};

二、岛屿数量

题目解析

给定一个n*m的二维数组,其中1表示陆地、0表示海洋;

多个相邻的陆地可以看做是一座岛屿,要求计算网格中岛屿的数量。

算法思路

这道题也是一道典型的BFS/DFS的题目了,整体思路:

遍历grid数组,遍历到陆地(1)并且该陆地没有和其他陆地形成岛屿(没有被BFS/DFS遍历过),就从该节点进行一次BFS/DFS遍历。

这样我们只需要统计在遍历grid时,进行BFS/DFS的次数即可。

这里使用BFS来解决这道题问题。

代码实现

cpp 复制代码
class Solution {
public:
    typedef pair<int, int> PII;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    bool vis[310][310] = {false};
    int numIslands(vector<vector<char>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        int ret = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == '1' && vis[i][j] == false) {
                    ret++;
                    bfs(grid, i, j);
                }
            }
        }
        return ret;
    }
    void bfs(vector<vector<char>>& grid, int i, int j) {
        // bfs遍历
        int n = grid.size();
        int m = grid[0].size();
        queue<PII> q;
        q.push({i, j});
        vis[i][j] = true;
        while (q.size()) {
            // 层序
            auto [a, b] = q.front();
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '1' &&
                    vis[x][y] == false) {
                    q.push({x, y});
                    vis[x][y] = true;
                }
            }
        }
    }
};

三、岛屿的最大面积

题目解析

这道题和求岛屿数量可以说是大同小异,这道题要求我们求出岛屿的最大面积。

算法思路

这道题的结题思路也是和求岛屿数量大同小异;

还是遍历grid数组,在遍历到陆地并且该陆地没有和其他陆地组成岛屿。(遍历到1并且该位置没有被遍历过)

就从该位置进行一次BFS遍历(DFS也可以解决),并求出岛屿的面积;

然后统计岛屿面积的最大值然后返回即可。

代码实现

cpp 复制代码
class Solution {
public:
    typedef pair<int, int> PII;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int vis[55][55] = {false};
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        int ret = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && vis[i][j] == false) {
                    int tmp = bfs(grid, i, j);
                    ret = max(ret, tmp);
                }
            }
        }
        return ret;
    }
    int bfs(vector<vector<int>>& grid, int i, int j) {
        int n = grid.size();
        int m = grid[0].size();
        queue<PII> q;
        q.push({i, j});
        vis[i][j] = true;
        int ret = 1;
        while (q.size()) {
            auto [a, b] = q.front();
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1 &&
                    vis[x][y] == false) {
                    q.push({x, y});
                    vis[x][y] = true;
                    ret++;
                }
            }
        }
        return ret;
    }
};

四、被围绕的区域

题目解析

这道题给定一个字符矩阵board,其中只包含XO

题目要求捕获所有被围绕的区域:一块相邻且都是O的区域,如果它不在边缘,就全部修改成X

算法思路

简单来说,这道题就是让我们将一块相邻且都是O,并且不在边缘的区域全部修改成X

这里如果直接去解决这个问题,还是有一点难度的(有进行BFS遍历时,还要判断它是否在边缘,不在边缘才能修改)。

直接去修改不行,那我们是不是可以先将在边缘的O区域进行标记(特殊处理);

然后再将没有标记的所有O都修改成X

最后,复原位于边缘的O区域。

这里可以创建一个等大的二维数组,来标记是否位于边缘;也可以先将位于边缘的O区域修改成不相干的字符,最后再复原即可。

代码实现

cpp 复制代码
class Solution {
public:
    typedef pair<int, int> PII;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    // bfs
    void bfs(vector<vector<char>>& board, vector<vector<bool>>& vis, int i,
             int j) {
        vis[i][j] = true;
        int n = board.size();
        int m = board[0].size();
        queue<PII> q;
        q.push({i, j});
        while (q.size() > 0) {
            auto [a, b] = q.front();
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < m && board[x][y] == 'O' &&
                    vis[x][y] == false) {
                    q.push({x, y});
                    vis[x][y] = true;
                }
            }
        }
    }
    void solve(vector<vector<char>>& board) {
        // 遍历四周的'o'
        int n = board.size();
        int m = board[0].size();
        vector<vector<bool>> vis(n, vector<bool>(m, false));
        for (int i = 0; i < m; i++) {
            if (board[0][i] == 'O' && vis[0][i] == false)
                bfs(board, vis, 0, i);
            if (board[n - 1][i] == 'O' && vis[n - 1][i] == false)
                bfs(board, vis, n - 1, i);
        }
        for (int i = 0; i < n; i++) {
            if (board[i][0] == 'O' && vis[i][0] == false)
                bfs(board, vis, i, 0);
            if (board[i][m - 1] == 'O' && vis[i][m - 1] == false)
                bfs(board, vis, i, m - 1);
        }
        for (int i = 1; i < n - 1; i++) {
            for (int j = 1; j < m - 1; j++) {
                if (board[i][j] == 'O' && vis[i][j] == false)
                    board[i][j] = 'X';
            }
        }
    }
};

本篇文章到这里就结束了,感谢支持

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

相关推荐
qq_433554542 小时前
C++数位DP
c++·算法·图论
AshinGau2 小时前
Softmax 与 交叉熵损失
神经网络·算法
似水এ᭄往昔2 小时前
【C++】--AVL树的认识和实现
开发语言·数据结构·c++·算法·stl
栀秋6662 小时前
“无重复字符的最长子串”:从O(n²)哈希优化到滑动窗口封神,再到DP降维打击!
前端·javascript·算法
xhxxx2 小时前
不用 Set,只用两个布尔值:如何用标志位将矩阵置零的空间复杂度压到 O(1)
javascript·算法·面试
有意义2 小时前
斐波那契数列:从递归到优化的完整指南
javascript·算法·面试
charlie1145141913 小时前
编写INI Parser 测试完整指南 - 从零开始
开发语言·c++·笔记·学习·算法·单元测试·测试
mmz12073 小时前
前缀和问题2(c++)
c++·算法
TL滕3 小时前
从0开始学算法——第十六天(双指针算法)
数据结构·笔记·学习·算法
蒲小英3 小时前
算法-贪心算法
算法·贪心算法