当前位置: 首页 > news >正文

算法:BFS解决 FloodFill 算法

目录

FloodFill 算法

题目一:图像渲染

题目二:岛屿数量

题目三:岛屿的最大面积

题目四:被围绕的区域


FloodFill 算法

在递归搜索回溯中已经说到过 FloodFill 算法了,但是那里是用 dfs 解决的,这里会使用 bfs 解决

FloodFill 算法(中文:洪水灌溉):

也就是找出性质相同的联通块

例如下图找出有几块会被洪水灌溉的区域,其中负数表示凹下去的地面,正数表示凸起的地面:

此时就会有两片区域会被洪水灌溉,也有问灌溉区域最大的面积是多少,或是灌溉区域最大的边是多少等等

按左边那个大的区域举例,之前的dfs,就是先一条路走到不能走时,再退回去,找其他路,也就是下面的紫色箭头的方式:

而bfs则是一层一层的扩展,每一层都关注该层的上下左右是否能扩展到其他地方,即下图所示:

共扩展了三层,就能够走完这个区域,这就是bfs的方式

总而言之,都是找出性质相同的联通块


题目一:图像渲染

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

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

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

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

示例 1:

输入: image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析: 在图像的正中间,(坐标(sr,sc)=(1,1)),在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。

示例 2:

输入: image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, newColor = 2
输出: [[2,2,2],[2,2,2]]

这道题的题意就是:给我们一个起始位置(sr, sc),找到与起始位置相连且像素值相同的区域,都修改为newColor

也就是使用层序遍历,先找出起始位置的上下左右是否有相连的相同数字块,找到后,接下来再找刚刚找到的这些数字块的上下左右,有没有相连的,直到没有为止

并且在扩展的过程中,将像素值再修改为 newColor

在书写bfs时,非常常用的技巧就是:设置两个数组dx和dy,他们对应的位置组合来表示上下左右的移动,即dx[4] = {0, 0, 1, -1},dy[4] = {1, -1, 0, 0}

对应位置组合为:(0, 1),(0, -1),(1, 0),(-1, 0)

让原本的坐标,加上对应的这四个坐标,就能够完美表示上下左右的移动

代码如下:

class Solution 
{// 简便表示pair,typedef重命名一下typedef pair<int, int> PII;int dx[4] = {0, 0, 1, -1};int dy[4] = {1, -1, 0, 0};
public:vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {// 记录原本的像素值int prev = image[sr][sc];int m = image.size(), n = image[0].size();// 边界条件if(prev == color) return image;queue<PII> q;q.push({sr, sc});// 层序遍历while(!q.empty()){// 这样可以简便的取出pair里的内容,不需要使用first,secondauto [a, b] = q.front();q.pop();image[a][b] = color;for(int i = 0; i < 4; i++){// x、y是上下左右移动后的新坐标int x = a + dx[i];int y = b + dy[i];// 需要判断x、y是否越界访问imageif(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == prev)q.push({x, y});}}return image;}
};

题目二:岛屿数量

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

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

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

示例 1:

输入:grid = [["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]
]
输出:1

示例 2:

输入:grid = [["1","1","0","0","0"],["1","1","0","0","0"],["0","0","1","0","0"],["0","0","0","1","1"]
]
输出:3

依旧是使用bfs的方式,这道题需要注意的是:

全是1的联通块是一个岛屿,但是在遍历时,有可能会重复计算同一块,假设第一块的右边第二块也是1,此时遍历到第一块时,会计算第二块,而遍历到第二块时,也可能会找到第一块,这样会导致死循环,一直遍历

解决方式就是创建一个与原数组一样大的数组vis,都是bool类型的,每遍历到一块区域,就将vis数组中对应位置的数设置为true,这样就不会重复遍历了

所以下面代码实现时,每次遍历到一个位置时,需要将vis数组中的该位置改为true,之后只有当vis数组对应位置为false时才遍历

代码如下:

class Solution 
{typedef pair<int, int> PII;// 判断数组,用于判断该位置是否被遍历过bool vis[301][301];int dx[4] = {0, 0, -1, 1};int dy[4] = {-1, 1, 0, 0};// m、n定义为全局的,便于bfs函数能取到值int m, n;
public:int numIslands(vector<vector<char>>& grid) {int ret = 0;m = grid.size(), n = grid[0].size();for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){// 当等于1时,还需要判断vis数组中对应位置是否为falseif(grid[i][j] == '1' && vis[i][j] == false){// 每进入一次层序遍历,表示找到了一个岛,ret++ret++;bfs(grid, i, j);}}}return ret;}// bfs层序遍历函数void bfs(vector<vector<char>>& grid, int i, int j){queue<PII> q;q.push({i, j});vis[i][j] = true;while(!q.empty()){auto [a, b] = q.front();q.pop();for(int num = 0; num < 4; num++){// 上下左右四块int x = a + dx[num];int y = b + dy[num];// 判断不越界的同时,还需要判断vis数组是否为falseif(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && vis[x][y] == false){// 每次遍历到后,将vis数组对应位置改为truevis[x][y] = true;q.push({x, y});}}}}
};

题目三:岛屿的最大面积

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

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

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

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

示例 1:

输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1

示例 2:

输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0

这道题与上一题一样,也是需要vis数组,标记某个位置是否遍历过,方法也与上一题几乎一模一样,只是在统计每一岛屿时,加了一个变量count,每次入队列时count++,最后返回给主函数即可

代码如下:

class Solution 
{
public:typedef pair<int, int> PII;// 判断数组,用于判断该位置是否被遍历过bool vis[60][60];int dx[4] = {0, 0, -1, 1};int dy[4] = {-1, 1, 0, 0};// m、n定义为全局的,便于bfs函数能取到值int m, n;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] == false){int num = bfs(grid, i, j);ret = max(ret, num);}}}return ret;}int bfs(vector<vector<int>>& grid, int i, int j){int count = 0;queue<PII> q;q.push({i, j});count++;vis[i][j] = true;while(!q.empty()){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){q.push({x, y});count++;vis[x][y] = true;}}}return count;}
};

题目四:被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' 组成,捕获 所有 被围绕的区域

  • 连接:一个单元格与水平或垂直方向上相邻的单元格连接。
  • 区域:连接所有 'O' 的单元格来形成一个区域。
  • 围绕:如果您可以用 'X' 单元格 连接这个区域,并且区域中没有任何单元格位于 board 边缘,则该区域被 'X' 单元格围绕。

通过将输入矩阵 board 中的所有 'O' 替换为 'X' 来 捕获被围绕的区域

示例 1:

输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]

输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]

解释:

在上图中,底部的区域没有被捕获,因为它在 board 的边缘并且不能被围绕。

示例 2:

输入:board = [["X"]]

输出:[["X"]]


题目要求就是联通块中不能存在边缘的方块,否则就不改变,边缘指 m * n 的四周那一圈

解法一:直接做

这道题最容易想到的思路就是直接做:

遇到联通块时,先遍历一下这个联通快,判断这个区域内是否有边缘块,如果没有就改变,如果有就不改变,这种做法是需要每次遍历两遍联通块,比较复杂,下面看解法二

解法二:正难则反

既然正着做这道题比较困难,那就反着做,题目要求不能联通块不能出现在边缘,所以我们可以先从边缘开始判断,对边缘区域的联通块先层序遍历,将这些边缘区域的○修改为+

此时矩阵中剩余的○就是符合题意的,这时遍历整个矩阵,如果有○全部修改为×

最后再将刚刚边缘改为+的位置,再改回○即可

代码如下:

class Solution {
public:typedef pair<int, int> PII;// 判断数组,用于判断该位置是否被遍历过int dx[4] = {0, 0, -1, 1};int dy[4] = {-1, 1, 0, 0};// m、n定义为全局的,便于bfs函数能取到值int m, n;void solve(vector<vector<char>>& board) {m = board.size(), n = board[0].size();// 将边缘区域为O的先全部变为+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 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);}// 再将剩余的O变为X,+变为Ofor(int i = 0; i < m; i++)for(int j = 0; j < n; j++)if(board[i][j] == 'O') board[i][j] = 'X';else if(board[i][j] == '+') board[i][j] = 'O';}// bfs实现边缘区域的O变+void bfs(vector<vector<char>>& board, int i, int j){queue<PII> 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];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] = '+';}}}}
};

BFS解决 FloodFill 算法的题目到此结束

相关文章:

算法:BFS解决 FloodFill 算法

目录 FloodFill 算法 题目一&#xff1a;图像渲染 题目二&#xff1a;岛屿数量 题目三&#xff1a;岛屿的最大面积 题目四&#xff1a;被围绕的区域 FloodFill 算法 在递归搜索回溯中已经说到过 FloodFill 算法了&#xff0c;但是那里是用 dfs 解决的&#xff0c;这里会使…...

Python 中文双引号 “”

Python 中文双引号 “” 1. SyntaxError: invalid character in identifier2. CorrectionReferences 1. SyntaxError: invalid character in identifier print(Albert Einstein once said, “A person who never made a mistake never tried anything new.”) print(Albert Ei…...

以太网(Ethernet)

目录 1. What is Internet?1.1. What is Ethernet?2. TCP/IP3. Physical Layer(PHY)4. Data Link Layer4.1. MAC Sublayer5. Network Layer5.1. IP5.2. ARP6. Transport Layer6.1. UDP6.2. TCP7. Application LayerFPGA实现以太网(一)——以太网简介 网络与路由交换 菜鸟FP…...

Scrcpy adb server version (41) doesn‘t match this client (39); killing...

通过Snap 在Ubuntu上安装 scrcpy之后&#xff0c;启动会导致无法同时 scrcpy和adb logcat 过滤日志 目前最新的安装的platforms-tools下面的adb 版本最新都是 adb 41版本 解决办法&#xff1a; 在这里链接里面 下载 adb 1.0.39 版本&#xff0c;替换 /home/host/Android/Sdk/…...

微服务实战系列之玩转Docker(四)

前言 幸福&#xff0c;就是继续追寻已经拥有的东西。 ——圣奥古斯丁 什么算已经拥有的&#xff1f;比如爱你的人在等你&#xff0c;比如每日热腾腾的三餐&#xff0c;比如身边可爱的同事&#xff0c;又比如此刻的你&#xff0c;看见了这篇博文&#xff08;&#x1f601;&#…...

微信小程序-自定义组件生命周期

一.created 组件实例创建完毕调用。定义在lifetimes对象里。 不能在方法里面更改data对象里面的值&#xff0c;但是可以定义属性值。 lifetimes:{//不能给data设置值created(){this.testaaconsole.log("created") }}二. attached 模板解析完成挂载到页面。 可以更…...

2024年7月23日(samba DNS)

​ 回顾 1、关闭防火墙&#xff0c;关闭selinux systemctl stop firewalld systemctl disable firewalld setenforce 0 2、修改静态IP地址 vim /etc/sysconfig/network-scripts/ifcfg-ens33 #修改uuid的目的是为了保证网络的唯一性 3、重启网络服务 systemctl restart netwo…...

Hyperledger顶级项目特点和介绍

Hyperledger的顶级项目 Hyperledger是Linux基金会主持的开源区块链项目&#xff0c;其目的是推动跨行业的区块链技术的开发和应用。以下是Hyperledger的顶级项目&#xff1a; 1. Hyperledger Fabric 描述&#xff1a;Hyperledger Fabric是一个可扩展的企业级区块链平台&…...

操作系统——笔记(1)

操作系统是管理计算机硬件资源&#xff0c;控制其他程序运行并为用户提供交互操作界面的系统软件的集合&#xff0c;控制和管理着整个计算机系统的硬件和软件资源&#xff0c;是最基本的系统软件。 常见的操作系统&#xff1a;ios、windows、Linux。 计算机系统的结构层次&am…...

isEmpty() 和 isBlank()的区别

isEmpty() 和 isBlank()的区别 平时自己开发的时候没有注意到这个地方,直到实习的时候代码审查的时候发现其用法上两者的不同. isEmpty() public static boolean isEmpty(String str) {return str null || str.length() 0; }isBlank() public static boolean isBlank(Strin…...

scrapy生成爬虫数据为excel

scrapy生成爬虫数据为excel 使用openpyxl&#xff08;推荐&#xff09;安装openpyxl库建一个新的Item Pipeline类在settings.py中启用ExcelPipeline说明 使用scrapy-xlsx首先&#xff0c;安装scrapy-xlsx&#xff1a;然后在Scrapy爬虫中使用管道&#xff1a;说明 要使用Scrapy生…...

vscode debug C++无法输入问题

研究了半天vscode debug c无法输入的问题&#xff0c;原来vscode的文档里面已经记录了。issue都是2020年提的了&#xff0c;还没解决。。。 不过人家也确实给了一个解法&#xff1a;用外部的terminal。 不过怎么看都还不是很方便&#xff0c;所以还是推荐直接使用CodeLLDB插件来…...

MODBUS tcp学习总结

MODBUS TCP协议实例数据帧详细分析_modbus 帧结构-CSDN博客...

【第一天】计算机网络 TCP/IP模型和OSI模型,从输入URL到页面显示发生了什么

TCP/IP模型和OSI模型 这两个模型属于计算机网络的体系结构。 OSI模型是七层模型&#xff0c;从上到下包括&#xff1a; 应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;网络层&#xff0c;数据链路层&#xff0c;物理层 TCP/IP模型是四层模型&…...

发现FionaAI:免费体验最新的GPT-4o Mini模型!

你现在可以在FionaAI上免费体验OpenAI刚刚发布的GPT-4o Mini模型&#xff01;作为您在Google Chrome中的ChatGPT驱动助手&#xff0c;FionaAI可以随时随地与您对话&#xff0c;帮助您轻松创作和处理文本。 为什么选择GPT-4o Mini&#xff1f; 最新技术&#xff1a;GPT-4o Mini是…...

Linux Gui 窗口对话和窗口操作

zenity 可以实现窗口对话 eg: zenity --error --width 300 --text "Permission denied. Cannot write to the file." ChosenDate$(zenity --calendar --text "Choose a date" --title "How-To Geek Rota" --day 1 --month 9 --year 2019); …...

人工智能驾驶技术:引领未来道路

随着科技的不断进步&#xff0c;人工智能驾驶技术正以惊人的速度改变着我们的交通方式和生活方式。这项技术不仅令人兴奋&#xff0c;还引发了许多关于安全性、道德和法律等方面的深思。本文将探讨人工智能自动驾驶技术的发展现状、应用前景以及对社会的影响。 技术背景与发展…...

管理的核心是管人,管人的核心就是这3条,看懂的是高手

管理的核心是管人&#xff0c;管人的核心就是这3条&#xff0c;看懂的是高手 一&#xff1a;管欲 每个人都有欲望&#xff0c;无可厚非。管理者的任务就是利用欲望&#xff0c;管理欲望&#xff0c;通过欲望来达到管人的目的。 最需要管理的就是以下两种&#xff1a; 1、金…...

代码解读:Diffusion Models中的长宽桶技术(Aspect Ratio Bucketing)

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;自从SDXL提出了长宽桶技术之后&#xff0c;彻底解决了不同长宽比的图像输入问题&#xff0c;现在已经成为训练扩散模型必选的方案。这篇博客从代码详细解读如何在模型训练的时候运用长宽桶技术(Aspect Rat…...

Linux下如何使用GitLab进行团队协作

在Linux系统中&#xff0c;使用GitLab进行团队协作是非常常见的做法。GitLab是一个基于Git的代码托管和项目管理平台&#xff0c;可以帮助团队成员共享、追踪和管理代码的开发过程。本文将介绍如何在Linux系统中安装和配置GitLab&#xff0c;以及一些常用的团队协作功能。 安装…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

Matlab实现任意伪彩色图像可视化显示

Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中&#xff0c;如何展示好看的实验结果图像非常重要&#xff01;&#xff01;&#xff01; 1、灰度原始图像 灰度图像每个像素点只有一个数值&#xff0c;代表该点的​​亮度&#xff08;或…...

归并排序:分治思想的高效排序

目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法&#xff0c;由约翰冯诺伊曼在1945年提出。其核心思想包括&#xff1a; 分割(Divide)&#xff1a;将待排序数组递归地分成两个子…...

Django RBAC项目后端实战 - 03 DRF权限控制实现

项目背景 在上一篇文章中&#xff0c;我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统&#xff0c;为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...

Java设计模式:责任链模式

一、什么是责任链模式&#xff1f; 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09; 是一种 行为型设计模式&#xff0c;它通过将请求沿着一条处理链传递&#xff0c;直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者&#xff0c;…...

Cursor AI 账号纯净度维护与高效注册指南

Cursor AI 账号纯净度维护与高效注册指南&#xff1a;解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后&#xff0c;许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...