FloodFill算法---DFS

目录

floodfill算法概念:

算法模板套路: 

例题1:图像渲染

例题2:岛屿数量

例题3:岛屿的最大面积

例题4:被围绕的区域


floodfill算法概念:

floodfill算法是一种常用的图像处理算法,用于填充连通区域。它从指定的种子点开始,将相邻的像素点按照某种条件进行填充,直到所有符合条件的像素点都被填充为止。floodfill算法常用于图像处理中的填充、边界提取、区域分割等任务。它可以用于实现画图工具中的油漆桶工具,也可以用于图像分割中的区域填充。

floodfill算法的中文名为洪水灌溉算法,基本实现内容:从某个点开始向四周扩散,直到无法再扩散为止。(可以使用DFS和BFS,本文讲解DFS解决)从这个实现内容我们不难发现这很适合我们利用爆搜来实现(一般数据范围不会太大)。如下图数字为1的就是一个性质相同的连通块。这类问题通常会问我们1的最大联通块是多大?或者有几个1的连通块?使用floodfill算法解决的题目基本一眼就能看得出来,不想滑动窗口和动态规划之类的算法,你不试一试是看不出来要使用什么算法的😭😭😭。

算法模板套路: 

创建所需的全局变量(最好设置为静态,因为非静态只有在leetcode上才行)

static boolean[][] vis;//( 不一定要有)

static int[ ] dx = {0 , 0 , 1 , -1 };

static int[ ] dy = {1 , -1 , 0 , 0 };

vis这个布尔类型数组来标记我们已经走过的路,防止重复走导致死循环。如果题目可以改给出的二维数组的值的话可以修改值就不用创建这个数组来标记了。

dx,dy数组配合使用,对应就是上下左右走,这是四个方向(上下左右)的,如果题目要求8个方向的话可以在草稿纸上画个图推一下很快的。

其他的一些条件根据题目的具体情况创建。

DFS模板如下:

其中n为行的个数,m为列的个数,至于要不要回溯要根据题目要求什么来决定。如果是8个方向的话把改一下dx和dy还有k的值变为8即可。x >= 0 && x < n && y >= 0 && y < m 这个可以说是默写了,因为这就是防止越界,每道题目都是这么写的。

public static void dfs(int i,int j,.....){for(int k = 0;k < 4;k++){int x = i + dx[k];int y = j + dy[k];if(x >=0 && x < n && y >= 0 && y < m && !vis[x][y] && 题目条件){vis[x][y] = true;dfs(x,y,.....);vis[x][y] = false;//回溯}}}

上面的这些是作者自己总结出来的,友友们刚开始可以试试,后面做的熟练了基本写出这些就是肌肉记忆了,这个在比赛中也会考到。

下面给出的例题前三题必看,可以说是floodfill算法的经典题型了。

例题1:图像渲染

链接:图像渲染

有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。

你也被给予三个整数 sr ,  sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。

为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应 四个方向上 像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为 newColor 。

最后返回 经过上色渲染后的图像 

详细题解: 

可以利用深搜,遍历到与该点相连的所有像素相同的点,然后将其修改成指定的像素即可。

这里再强调一下,在leetcode中不加static是可以的,但是在比赛中(要求自己写Main类)只能用static修饰的。 

直接对题目给出的一个点进行DFS,本题是直接在二位数组image的基础上直接修改那么就不用用到 vis 来标记了,因为走过的地方值被修改了那么就不会出现重复走的情况。具体代码如下:

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};int prev;int m,n;public int[][] floodFill(int[][] image, int sr, int sc, int color) {if(image[sr][sc] == color){return image;}prev = image[sr][sc];m = image.length;n = image[0].length;dfs(image,sr,sc,color);return image;}public void dfs(int[][] image,int i,int j,int color){image[i][j] = color;for(int k = 0;k < 4;k++){int x = i + dx[k];int y = j + dy[k];if(x >= 0 && x < m && y >=0 && y < n && image[x][y] == prev){dfs(image,x,y,color);}}}
}

例题2:岛屿数量

链接:岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

详细题解:

非常经典的一道floodfill算法题目其思路过程为:

遍历整个矩阵,每当找到一块陆地时,岛屿数量 + 1,并且将这个陆地相连的所有陆地,也就是这块岛屿,全部变成海洋。这样的话,我们下次遍历到这块岛屿的时候,它已经是海洋了,不会影响最终结果(当然也可以不修改矩阵,我们可以使用vis数组来完成去重操作)。变成海洋的操作可以利用DFS解决和上面给出的模板差不多😎😎😎

代码实现:

class Solution {static int ret;static boolean[][] vis;static int n;static int m;static int[] dx = {0,0,1,-1};static int[] dy = {1,-1,0,0};public static int numIslands(char[][] grid) {ret = 0;n = grid.length;m = grid[0].length;vis = new boolean[n][m];for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(grid[i][j] == '1' && !vis[i][j]){dfs(grid,i,j);ret++;}}}return ret;}public static void dfs(char[][] grid,int i,int j){vis[i][j] = true;for(int k = 0;k < 4;k++){int x = i + dx[k];int y = j + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '1' && !vis[x][y]){dfs(grid,x,y);}}}
}

例题3:岛屿的最大面积

链接:岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid 。

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

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

没错又是这张图因为比较经典且作者水平有限😭😭😭,所以就直接使用了。

详细题解:

遍历整个矩阵,每当遇到⼀块土地的时候,就用DFS将与这块土地相连的整个岛屿的面积计算出来。然后在搜索得到的所有岛屿面积中求一个最大值即可。这题我们就可以使用vis数组来标记这个位置是否已经被访问过了。

求这种最大值的又是深搜,建议大家自己设置一个变量来专门存储临时值和最大值,我一般存储临时值采用path,存储结果也就是最大值采用ret,step表示递归的层数(这个floodfill算法不涉及,在别的DFS题会用到)这个都行就是自己要明白。

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};int ret;boolean[][] vis;int n,m;int path;public int maxAreaOfIsland(int[][] grid) {n = grid.length;m = grid[0].length;vis = new boolean[n][m];ret = 0;for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(grid[i][j] == 1 && !vis[i][j]){path = 0;dfs(grid,i,j);ret = Math.max(ret,path);}}}return ret;}public void dfs(int[][] grid,int i,int j){vis[i][j] = true;path++;for(int k = 0;k < 4;k++){int x = i + dx[k];int y = j + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1 && !vis[x][y]){dfs(grid,x,y);}}}
}

相信做完上面三道题目,友友们是不是觉得有点没有意思,感觉就是在考背诵一样,DFS的写法基本差不多,上面的只要根据题意稍加修改即可。其实DFS确实差不多,有些难点是在如何使用DFS而不是写出DFS,例如下面的例题四,运用到了我们解决问题的经典思路正难则反

例题4:被围绕的区域

链接:被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

可以看到如果我们不加以转换的话直接按照我们前面三题的思路来的话有点困难,因为要判断很多边界情况,且要进行两遍DFS,所以我们要想一种更为巧妙的解法:正难则反。

解题过程:

可以先利用dfs将与边缘相连的'0' 区域做上标记,然后重新遍历矩阵,将没有标记过的'0' 修改成'X' 即可。就是这么的简单。遍历边缘就画个图模拟一下即可,至于DFS的编写那还不是手到擒来🤩🤩🤩 ,具体代码如下:

class Solution {int[] dx = {0,0,1,-1};int[] dy = {1,-1,0,0};boolean[][] vis;int n,m;public void solve(char[][] board) {n = board.length;m = board[0].length;vis = new boolean[n][m];//标记visfor(int i = 0;i < n;i++){if(board[i][0] == 'O'){dfs(board,i,0);}if(board[i][m - 1] == 'O'){dfs(board,i,m - 1);}}for(int i = 0;i < m;i++){if(board[0][i] == 'O'){dfs(board,0,i);}if(board[n - 1][i] == 'O'){dfs(board,n - 1,i);}}//将O用X填充for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){if(board[i][j] == 'O' && !vis[i][j]){board[i][j] = 'X';}}}}public void dfs(char[][] board,int i,int j){vis[i][j] = true;for(int k = 0;k < 4;k++){int x = i + dx[k];int y = j + dy[k];if(x >= 0 && x < n && y >= 0 && y < m && board[x][y] == 'O' && !vis[x][y]){dfs(board,x,y);}}}
}

总结:这类题难点在如何使用DFS,全局变量要根据具体情况来创建,这些搞定后写个DFS就是默写的事情。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

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

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

相关文章

高速AI光模块–通往400G/800G及更高速率

人工智能&#xff08;AI&#xff09;领域对高速数据传输的需求推动了光学技术取得显著进步。本文探讨了实现400G/800G速率的演进历程并展望这些技术在未来能够提供更强大功能。我们深入研究高速400G/800G AI光模块的需求、演变和重要性&#xff0c;展现它们对各个行业的变革性影…

Python 在windows环境下加密文件成.pyd格式

首先 pip install easycython然后打开在要加密的文件同一目录下cmd命令框&#xff0c;命令行里键入 easycython 你要加密的文件.py 最后会在目录下看见有个.pyd的文件&#xff0c;只保留这个文件&#xff0c;剩下的都删了&#xff0c;其他引用该文件的python文件该咋用咋用。…

element -ui 横向时间轴,时间轴悬浮对应日期

效果&#xff1a; <el-tabs v-model"activeName" type"card" tab-click"handleClick"><el-tab-pane label"周期性巡视" name"zqxxs" key"zqxxs" class"scrollable-tab-pane"><div v-if…

【11-Ⅱ】Head First Java 学习笔记

HeadFirst Java 本人有C语言基础&#xff0c;通过阅读Java廖雪峰网站&#xff0c;简单速成了java&#xff0c;但对其中一些入门概念有所疏漏&#xff0c;阅读本书以弥补。 第一章 Java入门 第二章 面向对象 第三章 变量 第四章 方法操作实例变量 第五章 程序实战 第六章 Java…

vlan的学习笔记2(vlan间通信)

1.使用路由器的物理接口 原理&#xff1a;在二层交换机上配置VLAN&#xff0c;每个VLAN单独使用一个交换机接口与路由器互联。路由器使用两个物理接口&#xff0c;分别作为VLAN 10及VLAN 20内PC的默认网关&#xff0c;使用路由器的物理接口实现VLAN之间的通信。 实验1&#x…

EasyCVR视频汇聚平台无法自动播放视频的原因排查与解决

国标GB28181协议EasyCVR安防视频监控平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流…

手撕sql面试题:根据分数进行排名,不使用窗口函数

分享一道面试题&#xff1a; 有一个分数表id 是该表的主键。该表的每一行都包含了一场考试的分数。Score 是一个有两位小数点的浮点值。 以下是表结构和数据&#xff1a; Create table Scores ( id int(11) NOT NULL AUTO_INCREMENT, score DECIMAL(3,2), PRIMARY KEY…

通过nrm管理源地址

安装nrm npm install -g nrm版本及帮助 Options:-V, --version 查看版本号-h, --help 帮助命令如下图 常用命令 Commands:ls 全部注册数据源列表current [options] 显示当前使用的…

ICCV2023人脸识别TransFace论文及代码学习笔记

论文链接&#xff1a;https://arxiv.org/pdf/2308.10133.pdf 代码链接&#xff1a;GitHub - DanJun6737/TransFace: Code of TransFace 背景 尽管ViTs在多种视觉任务中展示了强大的表示能力&#xff0c;但作者发现&#xff0c;当应用于具有极大数据集的人脸识别场景时&#…

SpringMVC 源码剖析

SpringMVC 源码剖析 0 从源码角度分析SpringMVC执行流程 // 前端控制器&#xff0c;SpringMVC最核心的类 public class DispatcherServlet extends FrameworkServlet {// 前端控制器最核心的方法&#xff0c;这个方法是负责处理请求的&#xff0c;一次请求&#xff0c;调用一次…

C语言趣味代码(三)

这一篇主要围绕写一个程序---寻找数字 来写&#xff0c;在这篇我会详细和大家介绍基本实现以及它的改良版&#xff0c;还有相关知识的拓展&#xff0c;干货绝对满满。 1. 寻找数字 在这一主题下&#xff0c;我们会编写一些代码&#xff0c;来锻炼玩家的反应力&#xff0c;同时…

Vue2学习笔记(尚硅谷天禹老师)

目录 一、入门案例 二、模板语法 三、数据绑定 四、el和data的两种写法 五、MVVM模型 六、Object.defineproperty方法 七、Vue中响应式原理 八、数据代理 九、methods配置项 十、Vue中的事件处理 十一、Vue中的键盘事件 十二、计算属性 十三、监视属性watch 十四、绑定Class样式…

玩转微服务-SonarQube

这里写目录标题 第一节 SonarQube1.1 简介1.2 四个组成部分1.2.1 SonarQube服务器1.2.2 SonarQube数据库1.2.3 插件1.2.4 Scanner 1.3 工作流程 第二节 SonarQube的安装2.1 安装2.2 插件 第三节 P3C规范3.1 简介3.2 SonarQube 配置 P3C规范3.3 IDEA配置 P3C规范 第四节 Maven项…

Mybatis-动态SQL

黑马程序员JavaWeb开发教程 文章目录 一、Mybatis-XML映射文件1、XML映射文件&#xff08;1&#xff09;规范&#xff08;2&#xff09;MybatisX 二、Mybatis-动态SQL-if1、动态SQL2、 标签<if><where>3、示例 三、Mybatis-动态SQL-foreach根据 id 批量删除员工1、…

iOS - 多线程-atomic

文章目录 iOS - 多线程-atomic1. 源码分析1.1 get方法1.2 set方法 2. 一般不使用atomic的原因 iOS - 多线程-atomic atomic用于保证属性setter、getter的原子性操作&#xff0c;相当于在getter和setter内部加了线程同步的锁可以参考源码objc4的objc-accessors.mm它并不能保证使…

刚刚,ChatGPT重大更新!GPT-4更加聪明,已成毕业论文撰写润色修改最佳利器!

今天ChatGPT Plus版本做了升级。GPT-4增强了记忆功能&#xff0c;能够通过你的多次对话了解你的意图&#xff0c;并提供合适的回应&#xff0c;总结一句话就是&#xff1a;更加懂你&#xff01; ChatGPT到底能干什么&#xff1f;我简单总结一下&#xff1a; 翻译&#xff1a;中…

电商技术揭秘三十一:智能风控与反欺诈技术

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘二十八&#xff1a;安全与合规性保障 电商技术揭秘二十九&#xff1a;电商法律合规浅析 电商技术揭秘三十&#xff1a;知识产权保…

C++必修:从C到C++的过渡(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. 缺省参数 1.1. 缺省参数的使用 缺省参数是声明或定义函数时为函数的参数指定…

Java基础之JVM对象内存分配机制简介

一 对象内存分配 1.1 运行时数据区域 1.2 常见java应用启动JVM参数&#xff1a; -Xss&#xff1a;每个线程的栈大小(单位kb)-Xms&#xff1a;堆的初始大小&#xff0c;默认物理内存的1/64,示例&#xff1a;-Xms:4g -Xms:10m-Xmx&#xff1a;堆的最大可用大小&#xff0c;默认物…

(Java)队列

一.概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾&#xff08;Tail/Rear&#xff09; 出队列&#xff1a;进行删…