C++算法:BFS解决FloodFill算法

BFS解决FloodFill算法

1.图像渲染

FloodFill用BFS解决,从某个元素开始,入队列;执行一系列操作;再准备两个数组dx,dy,辅助遍历上下左右相邻元素。

有时也需要同样规模的标记数组visited,例如imagex y已被遍历,则对应visitedx y记为1,避免重复遍历陷入死循环。本题可以不使用标记数组,如果初始坐标的原始颜色与color相同时,直接结束返回image即可。

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

        q.push({ sr,sc });
        while (!q.empty())
        {
            auto [a, b] = q.front();//C++17
            q.pop();

            image[a][b] = color;

            for (int i = 0;i < 4;i++)
            {
                int x = a + dx[i], y = b + dy[i];
                if ((x >= 0 && x < m) && (y >= 0 && y < n) && image[x][y] == start)
                    q.push({ x,y });
            }
        }
        return image;
    }
};

2.岛屿数量

与上一题类似,此题要用到visited数组。在用dx,dy辅助遍历数组时,新坐标入队列后应该立刻在visited数组中记为1,否则会超时。

cpp 复制代码
class Solution
{
    int dx[4] = { 1,-1,0,0 };
    int dy[4] = { 0,0,1,-1 };
    int visited[300][300] = { 0 };
public:
    int numIslands(vector<vector<char>>& grid)
    {
        int m = grid.size(), n = grid[0].size();

        int ret = 0;
        queue<pair<int, int>> q;
        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                if (grid[i][j] == '0' || visited[i][j] == 1)
                    continue;
                q.push({ i,j });
                visited[i][j] = 1;
                while (!q.empty())
                {
                    auto [a, b] = q.front();
                    q.pop();

                    for (int k = 0;k < 4;k++)
                    {
                        int x = a + dx[k], y = b + dy[k];
                        if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && visited[x][y] == 0)
                        {
                            q.push({ x,y });
                            visited[x][y] = 1;
                        }
                    }
                }
                ret++;
            }
        }
        return ret;
    }
};

3.岛屿的最大面积

只需要在BFS过程中记录面积即可。

cpp 复制代码
class Solution
{
    int dx[4] = { 0,0,1,-1 };
    int dy[4] = { 1,-1,0,0 };
    int visited[50][50] = { 0 };
public:
    int maxAreaOfIsland(vector<vector<int>>& grid)
    {
        int m = grid.size(), n = grid[0].size();
        int ret = 0;
        queue<pair<int, int>> q;
        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                if (grid[i][j] == 0 || visited[i][j] == 1)
                    continue;
                int s = 0;  //面积
                q.push({ i,j });
                visited[i][j] = 1;
                while (!q.empty())
                {
                    auto [a, b] = q.front();
                    q.pop();
                    s++;
                    for (int k = 0;k < 4;k++)
                    {
                        int x = a + dx[k], y = b + dy[k];
                        if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && visited[x][y] == 0)
                        {
                            q.push({ x,y });
                            visited[x][y] = 1;
                        }
                    }
                }
                ret = max(ret, s);
            }
        }
        return ret;
    }
};

4.被围绕的区域

理解题意,上下左右相邻且元素都为字符O视作一个连通块,如果这个连通块被字符X包围,则把这个连通块的所有元素改为字符X;如果连通块中存在元素位于矩阵的四个边缘,则该连通块不被字符X包围。

遍历矩阵,对每个连通块BFS,如果被字符X完全包围,则进行处理,否则不处理。显然这个方法是比较麻烦的,我们可以采用正难则反的思想,先遍历矩阵的四个边缘,把字符O的连通块全部改为字符 ! ,再遍历矩阵,此时矩阵内的字符O连通块都必定是被字符X包围的,直接把字符O改为字符X,同时把字符 ! 恢复为字符O。

cpp 复制代码
class Solution
{
    int dx[4] = { 0,0,-1,1 };
    int dy[4] = { 1,-1,0,0 };
    int m = 0, n = 0;
public:
    void solve(vector<vector<char>>& board)
    {
        m = board.size(), n = board[0].size();

        //遍历0行、m-1行
        for (int j = 0;j < n;j++)
        {
            if (board[0][j] == 'O')
                BFS(board, 0, j);
            if (board[m - 1][j] == 'O')
                BFS(board, m - 1, j);
        }

        //遍历0列、n-1列
        for (int i = 0;i < m;i++)
        {
            if (board[i][0] == 'O')
                BFS(board, i, 0);
            if (board[i][n - 1] == 'O')
                BFS(board, i, n - 1);
        }

        for (int i = 0;i < m;i++)
        {
            for (int j = 0;j < n;j++)
            {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
                if (board[i][j] == '!')
                    board[i][j] = 'O';
            }
        }
    }
    void BFS(vector<vector<char>>& board, int i, int j)
    {
        queue<pair<int, int>> q;
        q.push({ i,j });
        board[i][j] = '!';
        while (!q.empty())
        {
            auto [a, b] = q.front();
            q.pop();
            for (int k = 0;k < 4;k++)
            {
                int x = a + dx[k], y = b + dy[k];
                if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O')
                {
                    q.push({ x,y });
                    board[x][y] = '!';
                }
            }
        }
    }
};
相关推荐
爱写代码的小朋友1 小时前
从零开始学 Win32 API:C++ 窗口编程实战(VS Code + MinGW-w64 命令行详解)
开发语言·c++
小小晓.2 小时前
C++:语句和作用域
开发语言·c++
fqbqrr2 小时前
2607C++,soui,xplayer视频播放器
c++·soui
wanderist.2 小时前
Lambda表达式在算法竞赛中的应用
java·开发语言·算法
zh路西法3 小时前
【10天速通ROS2-PX4无人机】(四) 关掉GPS和气压计,纯激光定位还能飞吗
c++·无人机·px4·ros2·卡尔曼滤波·fastlio2
稚南城才子,乌衣巷风流3 小时前
支配树(Dominator Tree)详解:概念、算法与应用
算法
稚南城才子,乌衣巷风流4 小时前
动态开点:原理、实现与应用场景
数据结构·算法
yyds_yyd_100864 小时前
1464. 数组中两元素的最大乘积(2026.07.27)
数据结构·c++·算法·leetcode