BFS 解决 FloodFill 算法(典型算法思想)—— OJ例题算法解析思路

news2025/5/24 19:52:14

目录

一、733. 图像渲染 - 力扣(LeetCode)

 算法代码:

 算法思路

基础参数

函数入口

检查条件

初始化 BFS

BFS 填充过程

返回结果

复杂度分析

总结

二、200. 岛屿数量 - 力扣(LeetCode) 

算法代码: 

算法思路

基础参数

函数入口

遍历网格

BFS 遍历

返回结果

复杂度分析

总结

三、695. 岛屿的最大面积 - 力扣(LeetCode) 

算法代码:

算法思路

基础参数

函数入口

遍历网格

BFS 遍历

返回结果

复杂度分析

总结

四、130. 被围绕的区域 - 力扣(LeetCode) 

算法代码: 

算法思路

基础参数

函数入口

处理边界上的 'O' 区域

还原棋盘

BFS 遍历

复杂度分析

总结


一、733. 图像渲染 - 力扣(LeetCode)

 算法代码:

class Solution {
    typedef pair<int, int> PII; // 定义坐标对
    int dx[4] = {0, 0, 1, -1}; // 四个方向的x偏移量
    int dy[4] = {1, -1, 0, 0}; // 四个方向的y偏移量

public:
    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 m = image.size(), n = image[0].size(); // 获取图像的尺寸
        queue<PII> q; // 初始化队列
        q.push({sr, sc}); // 将起始坐标入队

        while (!q.empty()) { // BFS循环
            auto [a, b] = q.front(); // 获取队首元素
            image[a][b] = color; // 将当前点的颜色设为目标颜色
            q.pop(); // 移除队首元素

            // 遍历四个方向
            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] == prev) {
                    q.push({x, y}); // 将符合条件的坐标入队
                }
            }
        }
        return image; // 返回填充后的图像
    }
};

 算法思路

  1. 基础参数

    • 使用 typedef pair<int, int> PII 定义一个坐标对,方便存储和操作点的坐标。

    • dx 和 dy 数组用于表示四个方向的移动(右、左、下、上)。

  2. 函数入口

    • floodFill 函数接收一个图像 image(二维数组),起始坐标 sr 和 sc,以及要填充的颜色 color

  3. 检查条件

    • 首先获取起始点的原始颜色 prev,如果该颜色已经是目标颜色 color,则直接返回原图像,避免不必要的操作。

  4. 初始化 BFS

    • 获取图像的尺寸 m 和 n

    • 使用一个队列 q 来管理待处理的坐标。

    • 将起始坐标 (sr, sc) 入队。

  5. BFS 填充过程

    • 进入循环,直到队列为空:

      • 从队列中取出当前坐标 (a, b)

      • 将该坐标的颜色设置为 color

      • 遍历四个方向,计算相邻坐标 (x, y)

      • 检查新坐标是否在图像范围内,以及该坐标的颜色是否与 prev 相同。如果满足条件,则将新坐标入队。

  6. 返回结果

    • 循环结束后,返回填充后的图像。

复杂度分析

  • 时间复杂度:O(N),N 为图像中像素的总数。在最坏情况下,所有像素都可能被访问。

  • 空间复杂度:O(N),队列在最坏情况下可能需要存储所有的像素。

总结

        这个实现有效地解决了洪水填充问题,通过广度优先搜索遍历所有与起始点相连的相同颜色区域并将其填充为目标颜色。可以根据需要调整该实现以适应更复杂的场景或者使用 DFS(深度优先搜索)来实现同样的功能。

 

二、200. 岛屿数量 - 力扣(LeetCode) 

算法代码: 

class Solution {
    int dx[4] = {1, -1, 0, 0}; // 表示上下左右的x偏移
    int dy[4] = {0, 0, 1, -1}; // 表示上下左右的y偏移
    bool vis[301][301]; // 记录访问状态
    int m, n; // 网格的行数和列数

public:
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size(); // 获取行数
        n = grid[0].size(); // 获取列数
        int ret = 0; // 初始化岛屿计数器
        for (int i = 0; i < m; i++) { // 遍历每一行
            for (int j = 0; j < n; j++) { // 遍历每一列
                if (grid[i][j] == '1' && !vis[i][j]) { // 找到一个新的岛屿
                    ret++; // 增加岛屿计数
                    bfs(grid, i, j); // 用BFS标记这个岛屿
                }
            }
        }
        return ret; // 返回岛屿总数
    }
    
    void bfs(vector<vector<char>>& grid, int i, int j) {
        queue<pair<int, int>> q; // 初始化队列
        q.push({i, j}); // 入队当前坐标
        vis[i][j] = true; // 标记为已访问
        while (q.size()) { // BFS循环
            auto [a, b] = q.front(); // 获取队首元素
            q.pop(); // 移除队首元素
            for (int k = 0; k < 4; k++) { // 遍历四个方向
                int x = a + dx[k], y = b + dy[k]; // 计算相邻坐标
                // 检查是否在边界内,并且为 '1' 且未访问
                if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && !vis[x][y]) {
                    q.push({x, y}); // 入队
                    vis[x][y] = true; // 标记为已访问
                }
            }
        }
    }
};

算法思路

  1. 基础参数

    • 使用 dx 和 dy 数组来表示四个方向的移动(上下左右)。

    • vis 数组用于标记已经访问过的网格,避免重复计算。

  2. 函数入口

    • numIslands 函数接收一个二维网格 grid 作为输入,返回岛屿的数量。

  3. 遍历网格

    • 计算网格的行数 m 和列数 n

    • 使用双重循环遍历每个格子:

      • 当遇到 '1' 且未被访问过时,说明找到了一个新的岛屿,计数器 ret 加一,并调用 bfs 函数来遍历和标记这个岛屿的所有部分。

  4. BFS 遍历

    • 在 bfs 函数中:

      • 初始化一个队列,将当前陆地坐标入队,并将其标记为已访问。

      • 进入循环,直到队列为空:

        • 从队列中取出当前坐标 (a, b)

        • 遍历四个方向,计算相邻坐标 (x, y)

        • 检查新坐标是否在网格范围内,且该坐标为 '1' 且未被访问过。如果满足条件,则将新坐标入队并标记为已访问。

  5. 返回结果

    • 循环完成后,返回计数器 ret 的值,表示岛屿的总数量。

复杂度分析

  • 时间复杂度:O(M * N),其中 M 是行数,N 是列数。在最坏情况下,所有格子都可能被访问一次。

  • 空间复杂度:O(M * N),用于存储访问状态 vis,在最坏情况下,可能需要存储整个网格的状态。

总结

        这个实现有效地解决了“岛屿数量”问题,通过广度优先搜索(BFS)遍历所有相连的陆地('1'),并将其标记为已访问,以避免重复计数。可以根据需要将 BFS 替换为深度优先搜索(DFS)以实现相同的功能。总之,该算法能够高效地计算出网格中的岛屿数量,尤其适用于处理大型的二维网格问题。

三、695. 岛屿的最大面积 - 力扣(LeetCode) 

算法代码:

class Solution {
    int dx[4] = {0, 0, 1, -1}; // 表示上下左右的x偏移
    int dy[4] = {1, -1, 0, 0}; // 表示上下左右的y偏移
    bool vis[51][51]; // 记录访问状态(假设最大网格为51x51)
    int m, n; // 网格的行数和列数

public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        m = grid.size(); // 获取行数
        n = grid[0].size(); // 获取列数
        int ret = 0; // 初始化最大面积计数器
        for (int i = 0; i < m; i++) { // 遍历每一行
            for (int j = 0; j < n; j++) { // 遍历每一列
                if (grid[i][j] == 1 && !vis[i][j]) { // 找到一个新的岛屿
                    ret = max(ret, bfs(grid, i, j)); // 计算岛屿面积并更新最大面积
                }
            }
        }
        return ret; // 返回最大岛屿面积
    }
    
    int bfs(vector<vector<int>>& grid, int i, int j) {
        int count = 0; // 初始化当前岛屿面积计数
        queue<pair<int, int>> q; // 初始化队列
        q.push({i, j}); // 入队当前坐标
        vis[i][j] = true; // 标记为已访问
        count++; // 当前岛屿面积增加

        while (q.size()) { // BFS循环
            auto [a, b] = q.front(); // 获取队首元素
            q.pop(); // 移除队首元素
            for (int k = 0; k < 4; k++) { // 遍历四个方向
                int x = a + dx[k], y = b + dy[k]; // 计算相邻坐标
                // 检查是否在边界内,并且为 '1' 且未访问
                if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && !vis[x][y]) {
                    q.push({x, y}); // 入队
                    vis[x][y] = true; // 标记为已访问
                    count++; // 增加岛屿面积
                }
            }
        }
        return count; // 返回当前岛屿的面积
    }
};

算法思路

  1. 基础参数

    • dx 和 dy 数组用来表示四个方向的移动(右、左、下、上)。

    • vis 数组用于标记已经访问过的格子,以避免重复计算。

  2. 函数入口

    • maxAreaOfIsland 函数接收一个二维网格 grid 作为输入,返回最大的岛屿面积。

  3. 遍历网格

    • 计算网格的行数 m 和列数 n

    • 使用双重循环遍历每个格子:

      • 当遇到 1(陆地)且未被访问过时,调用 bfs 函数来计算这个岛屿的面积,并更新最大面积 ret

  4. BFS 遍历

    • 在 bfs 函数中:

      • 初始化一个计数器 count 用于记录岛屿的面积。

      • 将当前陆地坐标入队,并标记为已访问,同时将 count 增加。

      • 进入循环,直到队列为空:

        • 从队列中取出当前坐标 (a, b)

        • 遍历四个方向,计算相邻坐标 (x, y)

        • 检查新坐标是否在网格范围内,且该坐标为 1 且未被访问过。如果满足条件,则将新坐标入队并标记为已访问,同时增加 count

  5. 返回结果

    • 循环完成后,返回最大的岛屿面积 ret

复杂度分析

  • 时间复杂度:O(M * N),其中 M 是行数,N 是列数。在最坏情况下,所有格子都可能被访问一次。

  • 空间复杂度:O(M * N),用于存储访问状态 vis,在最坏情况下,可能需要存储整个网格的状态。

总结

        这个实现有效地解决了“最大岛屿面积”问题,通过广度优先搜索(BFS)遍历所有相连的陆地(1),并计算其面积。该算法能够高效地找到最大的岛屿面积,尤其适用于处理大型的二维网格问题。如果需要,也可以将 BFS 替换为深度优先搜索(DFS)以实现相同的功能。总之,该算法能够在给定的网格中快速找到并计算最大岛屿的面积。

四、130. 被围绕的区域 - 力扣(LeetCode) 

算法代码: 

class Solution {
    int dx[4] = {0, 0, 1, -1}; // 表示上下左右的x偏移
    int dy[4] = {1, -1, 0, 0}; // 表示上下左右的y偏移
    int m, n; // 棋盘的行数和列数

public:
    void solve(vector<vector<char>>& board) {
        m = board.size(); // 获取行数
        n = board[0].size(); // 获取列数
        
        // 1. 处理边界上的 'O' 联通块,全部修改成 '.'
        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);
        }
        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);
        }
        
        // 2. 还原剩余的区域
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O') // 被围住的区域变为 'X'
                    board[i][j] = 'X';
                else if (board[i][j] == '.') // 安全的区域还原为 'O'
                    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.size()) { // BFS循环
            auto [a, b] = q.front(); // 获取队首元素
            q.pop(); // 移除队首元素
            for (int k = 0; k < 4; k++) { // 遍历四个方向
                int x = a + dx[k], y = b + dy[k]; // 计算相邻坐标
                // 检查是否在边界内,并且为 'O'
                if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O') {
                    q.push({x, y}); // 入队
                    board[x][y] = '.'; // 标记为已访问(安全)
                }
            }
        }
    }
};

算法思路

  1. 基础参数

    • dx 和 dy 数组用来表示四个方向的移动(上下左右)。

    • m 和 n 分别表示棋盘的行数和列数。

  2. 函数入口

    • solve 函数接收一个二维棋盘 board,用于处理其中的 'O' 区域。

  3. 处理边界上的 'O' 区域

    • 通过双重循环遍历棋盘的边界(第一行、最后一行、第一列、最后一列):

      • 当遇到 'O' 时,调用 bfs 函数,将其和与之相连的所有 'O' 修改为 '.',表示这些 'O' 是安全的,不会被围住。

  4. 还原棋盘

    • 遍历整个棋盘,将剩余的 'O' (被围住的)改为 'X',将 '.' 还原为 'O'

  5. BFS 遍历

    • 在 bfs 函数中:

      • 初始化一个队列,将当前坐标入队,并将其改为 '.'

      • 进入循环,直到队列为空:

        • 从队列中取出当前坐标 (a, b)

        • 遍历四个方向,计算相邻坐标 (x, y)

        • 检查新坐标是否在棋盘范围内,且该坐标为 'O',如果满足条件,则将新坐标入队并改为 '.'

复杂度分析

  • 时间复杂度:O(M * N),其中 M 是行数,N 是列数。在最坏情况下,所有格子都可能被访问一次。

  • 空间复杂度:O(M * N),用于存储队列和处理访问状态,尤其当整个棋盘都是 'O' 时,队列可能存储整个棋盘。

总结

        这个实现有效地解决了“被围绕的区域”问题,通过广度优先搜索(BFS)遍历所有与边界相连的 'O',并将其标记为安全区域。最终,该算法能够高效地将被围住的区域转变为 'X',而保证与边界相连的 'O' 区域保持不变。该算法非常适合处理类似的二维网格问题,通过 BFS 的方式可以灵活地处理不同的边界条件和连通性问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端导出word文件,并包含导出Echarts图表等

基础导出模板 const html <html><head><style>body {font-family: Times New Roman;}h1 {text-align: center;}table {border-collapse: collapse;width: 100%;color: #1118FF;font-weight: 600;}th,td {border: 1px solid black;padding: 8px;text-align: …

【复现DeepSeek-R1之Open R1实战】系列8:混合精度训练、DeepSpeed、vLLM和LightEval介绍

这里写目录标题 1 混合精度训练1.1 FP16和FP321.2 优点1.3 存在的问题1.4 解决办法 2 DeepSpeed3 vLLM3.1 存在的问题3.2 解决方法3.2.1 PagedAttention3.2.2 KV Cache Manager3.2.3 其他解码场景 3.3 结论 4 LightEval4.1 主要功能4.2 使用方法4.3 应用场景 本文继续深入了解O…

大模型面经:SFT和RL如何影响模型的泛化或记忆能力?

监督微调 (SFT) 和强化学习 (RL)都是目前大模型的基础模型后训练技术&#xff0c;像DeepSeek-R1、kimi等的训练方法都将两种技术应用到了极致。 如何去设计训练步骤&#xff08;先SFT再RL&#xff0c;还是直接RL&#xff09;都需要对SFT和RL的能力有较深刻的了解。 本篇就以面…

2025-02-20 学习记录--C/C++-PTA 7-27 冒泡法排序

一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ /** * 冒泡法实现升序 */#include <stdio.h>int main() {int N, // 整数个数 6K, // 扫描遍数 2num, // 待排序的整数 2 3 5 1 6 4numArr[100], // 待排序的整数合集 2 3 5 1…

RK3588配置成为路由器

文章目录 前言一、配置netplan二、安装hostapd1.创建hostapd.conf文件2.安装软件3.修改启动文件4.修改/etc/default/hostapd 文件 三、安装dnsmasq服务四、配置NET及重启验证五、常见问题总结 前言 RK3588开发板有两个网口&#xff0c;一个无线网卡。我需要配置为家用路由器模…

【数据挖掘】--算法

【数据挖掘】--算法 目录&#xff1a;1. 缺失值和数值属性处理1缺失值处理&#xff1a; 2. 用于文档分类的朴素贝叶斯3. 分治法&#xff1a;建立决策树4. 覆盖算法建立规则5. 挖掘关联规则6. 线性模型有效寻找最近邻暴力搜索&#xff08;Brute-Force Search&#xff09;kd树&am…

Huatuo热更新--如何使用

在安装完huatuo热更新插件后就要开始学习如何使用了。 1.创建主框渐Main 新建文件夹Main&#xff08;可自定义&#xff09;&#xff0c;然后按下图创建文件&#xff0c;注意名称与文件夹名称保持一致 然后新建场景&#xff08;Init场景&#xff09;&#xff0c;添加3个空物体…

基于Django快递物流管理可视化分析系统(完整系统源码+数据库+详细开发文档+万字详细论文+答辩PPT+详细部署教程等资料)

文章目录 基于Django快递物流管理可视化分析系统&#xff08;完整系统源码数据库详细开发文档万字详细论文答辩PPT详细部署教程等资料&#xff09;一、项目概述二、项目说明三、研究意义四、系统设计技术架构 五、功能实现六、完整系统源码数据库详细开发文档万字详细论文答辩P…

基于射频开关选择的VNA校准设计

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…

解决本地模拟IP的DHCP冲突问题

解决 DHCP 冲突导致的多 IP 绑定失效问题 前言 续接上一篇在本机上模拟IP地址。 在实际操作中&#xff0c;如果本机原有 IP&#xff08;如 192.168.2.7&#xff09;是通过 DHCP 自动获取的&#xff0c;直接添加新 IP&#xff08;如 10.0.11.11&#xff09;可能会导致 DHCP 服…

Elasticsearch7.1.1 配置密码和SSL证书

生成SSL证书 ./elasticsearch-certutil ca -out config/certs/elastic-certificates.p12 -pass 我这里没有设置ssl证书密码&#xff0c;如果需要设置密码&#xff0c;需要再配置给elasticsearch 在之前的步骤中&#xff0c;如果我们对elastic-certificates.p12 文件配置了密码…

毕业项目推荐:基于yolov8/yolo11的100种中药材检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

自用题库---面试使用

1、css中如何实现水平垂直居中 方法一&#xff1a;flex&#xff1a; display: flex; justify-content: center; align-item: center;方法二&#xff1a;绝对定位margin:auto: position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin:auto;方法三&#xff1a;已…

蓝桥杯好数

样例输入&#xff1a; 24 输出&#xff1a;7 输入&#xff1a;2024 输出&#xff1a; 150 思路&#xff1a;本题朴素方法的时间复杂度是O(n * log10(n)) &#xff0c;不超时。主要考察能否逐位取数&#xff0c;注意细节pi&#xff0c;这样不会改变i,否则会导致循环错误。 #in…

Jenkins 配置 Credentials 凭证

Jenkins 配置 Credentials 凭证 一、创建凭证 Dashboard -> Manage Jenkins -> Manage Credentials 在 Domain 列随便点击一个 (global) 二、添加 凭证 点击左侧 Add Credentials 四、填写凭证 Kind&#xff1a;凭证类型 Username with password&#xff1a; 配置 用…

用openresty和lua实现壁纸投票功能

背景 之前做了一个随机壁纸接口&#xff0c;但是不知道大家喜欢对壁纸的喜好&#xff0c;所以干脆在实现一个投票功能&#xff0c;让用户给自己喜欢的壁纸进行投票。 原理说明 1.当访问http://demo.com/vote/时&#xff0c;会从/home/jobs/webs/imgs及子目录下获取图片列表&…

mysql查看binlog日志

mysql 配置、查看binlog日志&#xff1a; 示例为MySQL8.0 1、 检查binlog开启状态 SHOW VARIABLES LIKE ‘log_bin’; 如果未开启&#xff0c;修改配置my.ini 开启日志 安装目录配置my.ini(mysql8在data目录) log-binmysql-bin&#xff08;开启日志并指定日志前缀&#xff…

BiRefNet C++ TensorRT (二分类图像分割)

BiRefNet C TensorRT &#xff08;二分类图像分割&#xff09; 利用TensorRT和CUDA的双边参考网络&#xff08;BiRefNet&#xff09;的高性能c实现&#xff0c;针对实时高分辨率二分类图像分割进行了优化。 BiRefNet c TENSORRT旨在有效地在GPU上运行双边参考分割任务。通过利…

【ARM】MDK在编译 i.MXRT1芯片的时候出现报错Error: L6079E

1、 文档目标 解决MDK在编译 i.MXRT1芯片的时候出现报错Error: L6079E 2、 问题场景 客户在使用NXP 的NXP i.MXRT1050的芯片进行工程构建的时候出现下面的报错信息&#xff1a; Error: L6079E: Subtool invocation error: Error executing armcc. The system could not find…

论文笔记(七十二)Reward Centering(二)

Reward Centering&#xff08;二&#xff09; 文章概括摘要2 简单的奖励中心 文章概括 引用&#xff1a; article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arXiv preprint arXiv:2405.0…