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

【优选算法】BFS解决FloodFill算法

在这里插入图片描述

目录

  • FloodFill算法简介
  • 一、[图像渲染](https://leetcode.cn/problems/flood-fill/description/)
  • 二、[岛屿数量](https://leetcode.cn/problems/number-of-islands/description/)
  • 三、[岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/description/)
  • 四、[被围绕的区域](https://leetcode.cn/problems/surrounded-regions/description/)
  • 结尾

FloodFill算法简介

Flood Fill 算法(漫水填充算法)是一种经典的图像处理技术,用于将连通区域内的所有像素替换为指定颜色。

核心思想

从起始点开始,递归或迭代地将与其连通且颜色相同的所有像素替换为目标颜色,直到所有连通像素被处理完毕。


一、图像渲染

题目描述

在这里插入图片描述

思路讲解
本道题会给我们起始点和目标颜色 ,让我们将二维数组中起始点与起始点连通并且与起始点颜色相同点的值修改为目标颜色 ,这里使用BFS解决,通过队列逐层处理所有与起始点原始颜色相同的连通像素(上下左右四个方向),并将其替换为目标颜色。以下是具体思路:

  1. 本道题需要在原二维数组中进行修改,这里先将 [sr, sc] 位置上的值保存为 oldcolor
  2. 将起始点 [sr, sc] 加入队列,作为 BFS 的起点,并立即将其颜色改为 color
  3. 重复以下步骤,直到队列为空
    • 从队列中取出一个点 [r, c],遍历其四个相邻点 [nr, nc]
    • 对每个相邻点,检查是否在二维数组范围内且颜色为 oldcolor
    • 若符合条件,将其颜色改为 color,并加入队列,继续处理其相邻点
  4. 所有连通区域已处理完毕,返回修改后的二维数组

编写代码

class Solution {// 坐标上下左右需要加的数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) {if (image[sr][sc] == color)return image;int rows = image.size() , cols = image[0].size();queue<pair<int, int>> qu;int oldcolor = image[sr][sc];qu.push({sr, sc});while(!qu.empty()){int qu_x = qu.front().first, qu_y = qu.front().second;image[qu_x][qu_y] = color;qu.pop();for(int i = 0 ; i < 4 ; i++){int x = qu_x + dx[i] , y = qu_y + dy[i] ;if(x >= 0 && x < rows && y >=0 && y < cols && image[x][y] == oldcolor)qu.push({x,y});}}return image;}
};

二、岛屿数量

题目描述
在这里插入图片描述

思路讲解
本道题给我们一个二维数组,想让我们找出岛屿的数量。

遍历二维数组中的每个位置,当遇到未访问的陆地(‘1’)时,通过 BFS 将其连通的所有陆地标记为 “已访问”(避免重复计数),并计数为一个岛屿,以下是具体思路:

  1. 初始化岛屿数量为 0,创建一个与原二维数组同等规模的二维数组,并全部初始化为false,表示该位置没有被访问过
  2. 依次检查网格中的每个位置 [i, j]
  3. 若当前位置为 ‘1’ 并且未被访问过,则岛屿数量加 1,并使用 BFS 处理整个连通岛屿
  4. BFS 标记连通陆地:
    • 将当前陆地 [i, j] 加入队列,并立即标记为 true(表示已访问,避免重复处理)
    • 从队列中取出陆地,遍历其上下左右四个方向的相邻位置
    • 对每个相邻位置,若在网格范围内且为 ‘1’ 并且未被访问过,则标记为 true 并加入队列,继续扩展处理
  5. 遍历完所有位置后,返回岛屿数量

实际上标记岛屿已被访问,可以将 ‘1’ 改为 ‘0’ ,但是我这里为了不修改原数组,就创建一个二维数组,对应原二维数组,标记该位置是否访问过。

编写代码

class Solution {int dx[4] = {0, 0, -1, 1};int dy[4] = {1, -1, 0, 0};public:int numIslands(vector<vector<char>>& grid) {// 与grid同规模的数组,false代表还没走过,true代表已经走过vector<vector<bool>> vis(grid.size(),vector<bool>(grid[0].size(), false));queue<pair<int, int>> qu;int ans = 0;int rows = grid.size(), cols = grid[0].size();for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if (grid[i][j] == '1' && vis[i][j] == false) {ans++;vis[i][j] = true;qu.push({i, j});while (!qu.empty()) {int qu_x = qu.front().first, qu_y = qu.front().second;qu.pop();for (int k = 0; k < 4; k++) {int x = qu_x + dx[k], y = qu_y + dy[k];if(x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] == '1' && vis[x][y] == false){vis[x][y] = true;qu.push({x,y});}}}}}}return ans;}
};

三、岛屿的最大面积

题目描述
在这里插入图片描述

思路讲解
本道题给我们一个二维数组,想让我们找出最大岛屿。

遍历二维数组中的每个点,当遇到未访问的陆地(‘1’)时,通过 BFS 将其连通的所有陆地标记为 “已访问”(避免重复计数),并在BFS的过程中记录岛屿的大小,通过对比得到最大岛屿的大小,以下是具体思路:

  1. 初始化最多岛屿大小为 0,创建一个与原二维数组同等规模的二维数组,并全部初始化为false,表示该位置没有被访问过
  2. 依次检查二维数组中的每个点 [i, j]
  3. 若当前点为 ‘1’ 并且未被访问过,则岛屿数量加 1,并使用 BFS 处理整个连通岛屿
  4. BFS 标记连通陆地并记录陆地大小:
    • 初始化当前岛屿大小为0
    • 将当前陆地 [i, j] 加入队列,并立即标记为 true(表示已访问,避免重复处理)
    • 从队列中取出陆地,遍历其上下左右四个方向的相邻点
    • 对每个相邻点,若在二维数组范围内且为 ‘1’ 并且未被访问过,则将改点标记为 true ,加入队列并将当前岛屿大小+1,继续扩展处理
    • 一次BFS完成后,将当前岛屿大小与最大岛屿大小进行对比,获得最新最大岛屿大小
  5. 遍历完所有点后,返回岛屿数量

实际上标记岛屿已被访问,可以将 ‘1’ 改为 ‘0’ ,但是我这里为了不修改原数组,就创建一个二维数组,对应原二维数组,标记该点是否访问过。

编写代码

class Solution {int dx[4] = {0,0,-1,1};int dy[4] = {1,-1,0,0};
public:int maxAreaOfIsland(vector<vector<int>>& grid) {vector<vector<bool>> vis(grid.size(),vector<bool> (grid[0].size(),false));queue<pair<int,int>> qu;int rows = grid.size() , cols = grid[0].size();int ans = 0;for(int i = 0 ; i < rows ; i++){for(int j = 0 ; j < cols ; j++){if(grid[i][j] == 1 && vis[i][j] == false){qu.push({i,j});vis[i][j] = true;int tmp_max = 1;while(!qu.empty()){int qu_x = qu.front().first , qu_y = qu.front().second;qu.pop();for(int k = 0 ; k < 4 ; k++){int x = qu_x + dx[k] , y = qu_y + dy[k];if(x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] == 1 && vis[x][y] == false){vis[x][y] = true;qu.push({x,y});tmp_max++;}}}if(tmp_max > ans)ans = tmp_max;}}}return ans;}
};

四、被围绕的区域

题目描述
在这里插入图片描述

思路讲解
本道题给我们一个二维数组,想让我们将被 ‘X’ 包围的 'O’区域中的 ‘O’ 全部替换为 ‘X’,但是想直接找到被 ‘X’ 包围的 ‘O’ 并替换为 'X’需要两个步骤,首先是通过一次BFS判断该区域是否被包围,再通过一次BFS将被 ‘X’ 包围的 ‘O’ 替换为 ‘X’。

正向麻烦的话,就可以反向思考。先找出所有不被围绕的 ‘O’(即位于二维数组边缘或与边缘 ‘O’ 相连的 ‘O’),并将这些 ‘O’ 替换处 ‘O’ 和 ‘X’ 以外的字符;然后将剩余的 ‘O’(被围绕的区域)替换为 ‘X’。以下是具体思路:

  1. 遍历二维数组中边缘四条边中的每个位置 [i, j]
  2. 若当前位置为 ‘O’ ,将 ‘O’ 替换为 ‘H’,并使用 BFS 处理整个连通区域
  3. BFS 处理连通区域:
    • 将当前位置 [i, j] 加入队列
    • 从队列中取出位置,遍历其上下左右四个方向的相邻位置
    • 对每个相邻w位置,若在二维数组范围内且为 ‘O’ ,将 ‘O’ 替换为 ‘H’,继续扩展处理
  4. 将二维数组中所有的 ‘O’ 替换 ‘X’
  5. 将二维数组中所有的 ‘H’ 替换 ‘O’
  6. 处理完毕后,返回二维数组

编写代码

class Solution {int dx[4] = {0, 0, -1, 1};int dy[4] = {1, -1, 0, 0};int rows, cols;public:void bfs(vector<vector<char>>& board, vector<vector<bool>>& vis, int row , int col) {queue<pair<int, int>> qu;qu.push({row, col});board[row][col] = 'H';while (!qu.empty()) {int qu_x = qu.front().first, qu_y = qu.front().second;qu.pop();for (int k = 0; k < 4; k++) {int x = qu_x + dx[k], y = qu_y + dy[k];if (x >= 0 && x < rows && y >= 0 && y < cols &&board[x][y] == 'O' && vis[x][y] == false) {board[x][y] = 'H';qu.push({x, y});}}}}void solve(vector<vector<char>>& board) {rows = board.size(), cols = board[0].size();vector<vector<bool>> vis(rows, vector<bool>(cols, false));for (int i = 0; i < cols; i++) {if (board[0][i] == 'O' && vis[0][i] == false) {bfs(board, vis, 0 , i);}if (board[rows - 1][i] == 'O' && vis[rows - 1][i] == false) {bfs(board, vis, rows - 1, i);}}for (int i = 0; i < rows; i++) {if (board[i][0] == 'O' && vis[i][0] == false) {bfs(board, vis, i, 0);}if (board[i][cols - 1] == 'O' && vis[i][cols - 1] == false) {bfs(board, vis, i, cols - 1);}}for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if (board[i][j] == 'O')board[i][j] = 'X';else if (board[i][j] == 'H')board[i][j] = 'O';}}}
};

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述

http://www.lryc.cn/news/601176.html

相关文章:

  • Element表格单元格类名动态设置
  • VILA系列论文解读
  • 基于mnn架构在本地 c++运行llm与mllm模型
  • PostgreSQL AND OR 操作符详解
  • esp32s3创建rust工程 window成功mac
  • 前后端分离:架构模式与实践
  • Qt 分裂布局:QSplitter 使用指南
  • 四、搭建springCloudAlibaba2021.1版本分布式微服务-加入openFeign远程调用和sentinel流量控制
  • UNet 改进(38):融合多尺度输入与可变形卷积、门控特征融合的医学图像Unet分割网络
  • MySQL 事务和锁
  • 02人工智能中优雅草商业实战项目视频字幕翻译以及声音转译之以三方AI模型API制作方式预算-卓伊凡|莉莉
  • 车载诊断架构 ---面向售后的DTC应该怎么样填写?
  • KNN算法实战:手写数字识别详解
  • 前端基础班学习路线
  • Git+宝塔面板部署Hugo博客
  • net8.0一键创建辅助开发的个人小工具
  • 剑指offer第2版:双指针+排序+分治+滑动窗口
  • 零基础学习性能测试第五章:JVM性能分析与调优-GC垃圾分代回收机制与优化
  • 【嵌入式硬件实例】-555定时器调光电路实现
  • 工业控制系统安全之 Modbus 协议中间人攻击(MITM)分析与防范
  • DAY21-二叉树的遍历方式
  • 数据结构 堆(4)---TOP-K问题
  • Canvas实现微信小程序图片裁剪组件全攻略
  • mmap的调用层级与内核态陷入全过程
  • 六、搭建springCloudAlibaba2021.1版本分布式微服务-admin监控中心
  • 记录一次薛定谔bug
  • 基于LNMP架构的分布式个人博客搭建
  • Java大数据面试实战:Hadoop生态与分布式计算
  • 数据权属雷区:原始数据与衍生数据的法律边界如何划清?
  • AI与区块链Web3技术融合:重塑数字经济的未来格局