BFS:FloodFill算法

文章目录

  • FloodFill算法简介
  • 1.图像渲染
  • 2.岛屿数量
  • 3.岛屿的最大面积
  • 4.被围绕的区域
  • 总结

在这里插入图片描述

FloodFill算法简介

Flood Fill算法是一种用于确定与某个给定节点相连的区域的算法,常用于计算机图形学和图像处理。该算法可以用于诸如填充多边形、检测连通区域等任务。Flood Fill算法有多种实现方式,其中最常见的是递归方法和使用栈或队列的迭代方法。

基本思想
Flood Fill算法从一个初始像素开始,检查该像素的颜色。如果颜色匹配(即需要填充的颜色),则将其填充为新的颜色,然后对相邻的像素重复这一过程,直到所有相连的匹配像素都被填充为止。

在这里插入图片描述
FloodFill算法也叫洪水灌溉法,上图中0表示岛屿,1表示海洋,如果要我们求岛屿的个数的话就可以用洪水灌溉法则。

在这里插入图片描述

灌溉之后就像上面一样。
接下来,我们来练习几道题熟悉一下FloodFill算法。

1.图像渲染

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题的意思很简单,就是我们固定一个位置,这个位置的坐标是[sr,sc]这个位置周围的和这个这个区块数字相同数都会被变成新的数字。
以上面这个例子为例,初始坐标是中间坐标,那么渲染的区块就是:
在这里插入图片描述
在这里插入图片描述
如果利用FloodFill算法的话,我们按顺序灌溉应该是1->2->3->4。

算法原理:
利用BFS的FloodFill算法,这个算法我们只需要借助队列,每次入队列的时候改变当前节点的值。

代码展示:

class Solution {
public:
    typedef pair<int,long> PIL;
    //定义一个方向数组,上下左右四个位置
    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];
        int m=image.size();
        int n=image[0].size();
        if(prev==color)
        {
            return image;//处理边界情况
        }
        queue<PIL> q;
        q.push({sr,sc});
        while(q.size())
        {
            auto [a,b]=q.front();
            q.pop();
            image[a][b]=color;
            for(int i=0;i<4;i++)
            {
                int x=a+dx[i];
                int y=b+dy[i];
                if(x>=0&&x<m&&y>=0&&y<n&&image[x][y]==prev)
                {
                    q.push({x,y});
                }
            }
        }
        return image;
    }
};

2.岛屿数量

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

我们来看示例1:
在这里插入图片描述
这道题1是岛屿,0是海,然后这个数组的周围默认都是海。

算法原理:
这道题和上道题的思路是一样的,但是还多出来一步,就是当我们利用bfs来遍历数组的时候,假如我们从第一个位置开始遍历,遍历了一遍,记录了一个岛屿,但是我们第二次遍历的时候从第二个位置的1开始遍历,但是第二个位置的1是属于第一个岛屿的,所以这里就会产生重复,解决这种重复问题的办法就是开一个bool类型的vis数组,这个数组的大小和给定的数组的大小是相同的,我们每访问一个岛屿就将这个岛屿上对应的vis变为true,表示我们已经访问过这个节点了,所以这里进行bfs的条件多了一个不仅需要这个节点的值是1,还需要这个节点对应的vis数组是true。

代码展示:

class Solution {
public:
    typedef pair<int,int> PIL;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    bool vis[301][301];
    int ret=0;
    int m,n;
    void bfs(vector<vector<char>>& grid,int i,int j)
    {
        queue<PIL> q;
        q.push({i,j});
        vis[i][j]=false;
        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 < m && x >= 0 && y >= 0&&y<n&&grid[x][y]=='1'&&vis[x][y]==false)
                {
                    vis[x][y]=true;
                    q.push({x,y});
                }
            }
        }
    }
    int numIslands(vector<vector<char>>& grid) 
    {
        m=grid.size();
        n=grid[0].size();
        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                if(grid[i][j]=='1'&&vis[i][j]==false)
                {
                    bfs(grid,i,j);//将这个陆地标记一下
                    ret++;
                }
            }
        }
        return ret;
    }
};

3.岛屿的最大面积

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题的背景和上一道题是一样的,但是这道题不是让我们求岛屿的数量而是让我们求所有岛屿中面积最大的那个岛屿大面积

算法原理:
这道题需要的变量和上道题也是一样的,但是唯一不同的一点是上一道题是void,这道题是int,所以我们需要记录每次BFS的结果,我们用S记录每次BFS的结果,然后每次BFS之后,和前一次求出来的面积进行比较,最后直接返回最大值。

代码展示:

class Solution {
public:
    typedef pair<int,int> PIL;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    bool vis[51][51];
    int m,n;
    int S;
    int bfs(vector<vector<int>>& grid,int i,int j)
    {
        int Sum=0;
        queue<PIL> q;
        q.push({i,j});
        Sum++;
        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<m&&y>=0&&y<n&&grid[x][y]==1&&vis[x][y]==false)
                {
                    vis[x][y]=true;
                    q.push({x,y});
                    Sum++;
                }
            }
        }
        return Sum;
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) 
    {
        m=grid.size();
        n=grid[0].size();
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
               if(grid[i][j]==1&&vis[i][j]==false)
               {
                    int S1=bfs(grid,i,j);
                    if(S<S1)
                    {
                        S=S1;
                    }
               }
            }
        }
        return S;
    }
};

4.被围绕的区域

题目链接
题目:

在这里插入图片描述

样例输入和输出:

在这里插入图片描述

这道题给出的二维数组中的值只有X和O,这道题的意思就是让我们修改被x包围的O为x,然后边界的联通区域不需要修改。
我们用一个例子来表示上面的题意:
在这里插入图片描述

蓝色区域表示不能修改的边界联通区域,灰色区域表示被X围住的中间的需要修改的联通区域。

算法原理,如果这道题我们直接正面做的话,很难,因为当我们进行BFS的时候,我们并不知道这块区域是边界联通的区域,就像下面这种情况:
在这里插入图片描述
上面这种情况,当我们从第一个位置开始BFS我们到后面才知道这个联通区域是边界区域,但是我们又不能倒过去找,所以我们只能先标记这个边界区域,然后再用一次BFS对可修改区域进行修改,所以这里我们先对边界区域进行遍历,先把边界区域修改为另一个字符,这里我们将这个字符定义为’*'修改了之后,我们只需要对这个二维数组遍历一遍,将O修改为X,将 *修改为O即可。

代码展示:

class Solution {
public:
    typedef pair<int,int> PII;
    int m,n;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    void bfs(vector<vector<char>>& board,int i,int j)
    {
        queue<PII> q;
        q.push({i,j});
        board[i][j]='*';
        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<m&&y>=0&&y<n&&board[x][y]=='O')
                {
                    q.push({x,y});
                    board[x][y]='*';
                }
            }
        }
    }
    void solve(vector<vector<char>>& board) {
        m=board.size();
        n=board[0].size();
        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);
        }
        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';
            }
        }
    }
};

总结

Flood Fill算法在图像处理和计算机图形学中扮演着重要角色。无论是用于简单的填色任务,还是复杂的区域检测,这一算法都展示了其强大的功能。本文详细介绍了Flood Fill算法的基本思想,并提供了递归和迭代两种实现方式。递归方法虽然简单直观,但在处理较大图像时可能会遇到递归深度的限制;而迭代方法则通过显式管理待填充的像素,克服了这一问题。

通过这两种实现方法的比较,我们不仅了解了Flood Fill算法的原理,也掌握了如何选择合适的实现方式来应对不同的应用场景。希望这篇博客能帮助大家更好地理解和应用Flood Fill算法,在实际项目中解决相关问题。

如果您有任何问题或需要进一步讨论,欢迎在评论区留言。感谢您的阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 一键部署 Nginx1.26.1 + ModSecurity3

前言 ModSecurity 是 Apache 基金会的一个开源、高性能的 Web 应用程序防火墙(WAF),它提供了强大的安全规则引擎,用于检测和阻止各种攻击行为,如 SQL 注入、XSS 跨站点脚本攻击等。而 nginx 是一个高性能的 Web 服务器,常用于处理大量的并发请求,具有很高的负载均衡能力…

蓝牙数传芯片TD5325A,蓝牙5.1—拓达半导体

拓达TD5325A芯片是一款支持蓝牙BLE&SPP的纯数传芯片&#xff0c;蓝牙5.1版本。芯片的亮点在于性能强&#xff0c;支持APP端直接对芯片做设置与查询操作&#xff0c;包括修改蓝牙名、UUID、MAC地址&#xff0c;以及直接操作蓝牙芯片自身的IO与PWM口&#xff0c;还包括支持简…

Linux:用户账号和权限管理的命令

目录 一、Linux用户的分类和组的分类 1.1、用户账号和组账号 1.2、用户的分类 1.3、组账号 1.4、用户账号文件/etc/passwd 二、用户管理相关命令 2.1、chage命令&#xff1a;用来修改帐号和密码的有效期限&#xff0c;针对目前系统已经存在的用户 2.2、useradd&#xf…

行车记录仪文件夹“0字节”现象解析与恢复策略

一、行车记录仪文件夹“0字节”现象描述 行车记录仪作为现代驾驶中的必备设备&#xff0c;其储存的视频数据对于事故记录和取证至关重要。然而&#xff0c;有时车主们可能会遇到这样一个问题&#xff1a;行车记录仪的某个文件夹内的文件突然变成了0字节大小&#xff0c;无法正…

Vue快速上手和Vue指令

一、Vue快速上手 1、Vue概念 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套构建用户界面的渐进式框架 Vue2官网&#xff1a;https://v2.cn.vuejs.org/ 构建用户界面&#xff1a;基于数据渲染出用户可以看到的界面 渐进式&#xff1a; 循序渐进&#xff0c;不一定非得把…

操作系统精选题(一)(PV经典问题之生产者与消费者)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;操作系统 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 进程互斥与同步 题目一 题目二 题…

开发uniapp插件包aar文件,使uniapp可以调用jar包

背景 使用 uniapp 开发应用时&#xff0c;很多时候都需要调用第三方的sdk&#xff0c;一般以 jar 为主。为了应对这个问题&#xff0c;官方提供了插件方案&#xff0c;可以将第三方 jar 包进行封装为 aar 包后&#xff0c;再集成到 uniapp 中使用。 一、环境安装工具 1、jdk…

后台管理台字典localStorage缓存删除

localStorage里存放了如以下dictItems_开头的字典数据&#xff0c;localStorage缓存是没有过期时间的&#xff0c;需要手动删除。同时localStorage里还存有其他不需要删除的数据。 这里的方案是遍历localStorage&#xff0c;利用正则和所有key进行匹配&#xff0c;匹配到dict…

qt打包失败 ,应用程序无法正常启动0xc000007b解决办法

用 windeployqt 打包QT程序&#xff0c;运行时提示程序无法正常启动0xc000007b #原因&#xff1a;因本机装了多个版本的Qt&#xff0c;包括32位&#xff0c;64位的&#xff0c;在cmd下可能是环境变量原因&#xff0c;用 windeployqt 打的包无法运行 解决办法&#xff1a; 1、…

【netty】三万字详解!JAVA高性能通信框架,关于netty,看这一篇就够了

目录 1.概述 2.hello world 3.EventLoop 4.channel 4.1.同步 4.2.异步 4.3.调试 4.4.关闭 4.5.为什么要用异步 5.future 6.promise 7.pipeline 8.byteBuf 8.1.创建 8.2.内存模式和池化 8.2.1.内存模式 8.2.2.池化 8.3.组成 8.4.操作 8.4.1.读写 8.4.2.释放…

内容安全复习 2 - 网络信息内容的获取与表示

文章目录 信息内容的获取网络信息内容的类型网络媒体信息获取方法 信息内容的表示视觉信息视觉特征表达文本特征表达音频特征表达 信息内容的获取 网络信息内容的类型 网络媒体信息 传统意义上的互联网网站公开发布信息&#xff0c;网络用户通常可以基于网络浏览器获得。网络…

数据结构_优先级队列(堆)

目录 一、优先级队列 1.1 堆 1.2 PriorityQueue接口 二、模拟实现优先级队列 2.1 初始化 2.2 创建大根堆 (向下调整) 2.3 堆的插入 2.4 堆的删除 2.5 堆排序 总结 一、优先级队列 优先级队列是一种特殊的队列&#xff0c;其出队顺序与入队顺序无关&#xff0c;而与优…

Unet已死,Transformer当立!详细解读基于DiT的开源视频生成大模型EasyAnimate

Diffusion Models视频生成-博客汇总 前言&#xff1a;最近阿里云PIA团队开源了基于Diffusion Transformer结构的视频生成模型EasyAnimate&#xff0c;并且提出了专门针对视频的slice VAE&#xff0c;对于目前基于Unet结构的视频生成最好如SVD形成了降维打击&#xff0c;不论是生…

16s功能注释--PICRUST2的安装及使用

文章目录 安装本地安装conda安装 使用一些报错 安装 本地安装 在github网址下载压缩包&#xff1a;https://github.com/picrust/picrust2/releases/tag/v2.5.2 解压后将bin目录设置到环境变量 conda安装 利用bioconda安装 conda create -n picrust2 -c bioconda -c conda-…

Matlab基础语法:变量和数据类型,基本运算,矩阵和向量,常用函数,脚本文件

目录 一、变量和数据类型 二、基本运算 三、矩阵和向量 四、常用函数 五、脚本文件 六、总结 一、变量和数据类型 Matlab 支持多种数据类型&#xff0c;包括数值类型、字符类型和逻辑类型。掌握这些基本的变量和数据类型&#xff0c;是我们进行数学建模和计算的基础。 数…

网络安全复习笔记

概述 要素 CIA&#xff1a;可用性&#xff1b;完整性&#xff1b;保密性。 可控性&#xff1b;不可否认性&#xff1b;可审查性。 攻击 被动&#xff1a;窃听 - 保密性&#xff1b;监听 - 保密性主动&#xff1a;假冒 - 完整性&#xff1b;重放 - 完整性&#xff1b;改写 -…

数学建模系列(4/4):Matlab建模实战

目录 引言 1. Matlab简介与安装 1.1 Matlab简介 1.2 Matlab的安装 2. Matlab基础操作 2.1 Matlab基础语法和常用命令 2.2 Matlab中的数据类型和数据结构 3. 用Matlab进行建模 3.1 矩阵运算与线性代数 矩阵运算 3.2 Matlab中的绘图功能 绘制2D图形 绘制3D图形 3.3…

中服云产品远程运维系统

中服云产品远程运维系统主要针对设备售后市场服务的管理&#xff0c;利用工业物联网技术&#xff0c;一方面面向设备生产厂商&#xff0c;将分散的经销商、客户、销售出去的设备统一管理&#xff1b;另一方面面向设备使用厂家&#xff0c;实现设备实时运行监控&#xff1b;系统…

【手机号性别查询、姓名查询、年龄查询、要素核验接口】支持高并发查询。

** 最近更新时间&#xff1a;2024-06-21 用户手机号注册实名认证接口&#xff0c;精度高&#xff0c;简化注册用户的认证流程&#xff0c;输入手机号码就可以获得认证结果&#xff0c;适合金融、社交、教育、电商、商户入驻等业务场景&#xff0c;用于简化实名认证流程&#…

AI网络爬虫:用deepseek提取百度文心一言的智能体数据

真实网址&#xff1a;https://agents.baidu.com/lingjing/experhub/search/list?pageSize36&pageNo1&tagId-99 返回的json数据&#xff1a;{ "errno": 0, "msg": "success", "data": { "total": 36, "p…