FloodFill算法---BFS

目录

一、前言

二、算法模板套路

2.1 创建所需的全局变量:

2.2 BFS模板:

2.3 细节处理:

三、例题练习

3.1 例题1:图像渲染

3.2 例题2:岛屿数量

3.3 例题3:岛屿的最大面积

3.4 例题4:被围绕的区域


一、前言

在这之前我们已经学习了如何使用 DFS 解决 FloodFill 算法,如果有友友对 FloodFill 算法不太熟悉的话可以先看看我之前写的文章:FloodFill算法---DFS。里面详细介绍了什么是FloodFill算法和如何使用DFS来解决。通常 FloodFill 算法使用 DFS 或者 BFS 都可以,DFS 的代码会简洁一些,但是 BFS 可以用来解决最短路问题拓扑排序。所以本文章可以说是为了后续使用 BFS 解决最短路问题和拓扑排序打下基础。

• 关于BFS的遍历特性:若初始点为左上角,遍历特性如下图所示。

二、算法模板套路

2.1 创建所需的全局变量:

最好设置为静态,因为非静态只有在leetcode上才行,在竞赛中都是要我们自己写Main类的因为main是静态方法所以在方法外面的全局变量要设置为静态的才能被main方法调用。

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

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

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

• vis这个布尔类型数组来标记我们已经走过的路,防止重复走导致死循环:

还有一种可以不用创建 vis 来标记,直接修改原来数据的值,这个如果是在面试的时候要问一下面试官,原来数组的数值是否可以修改。

• 利用dx,dy 来实现上下左右移动(如果是8个方向的也行):

for(int k = 0;k < 4;k++){
    int x = i + dx[k];
    int y = j + dy[k];
}

 如果是 8 个方向的话可以先画出下图。

在把黄色对应的8个位置写入到dx和dy中。例如:

下面这个例子是从上到下,从左到右写的。

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

2.2 BFS模板:

我们利用 int[ ]来存储坐标。

• 至于要不要回溯,要根据题目要求什么来进行决定。

• x >= 0 && x < n && y >= 0 && y < m 这个可以说是默写了,因为这就是防止越界,每道题目都是这么写的。

public void bfs(char[][] grid, int i, int j) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[] { i, j });
        while (!queue.isEmpty()) {
            int[] tmp = queue.poll();
            int a = tmp[0];
            int b = tmp[1];
            vis[a][b] = true;///1
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y]){
                    queue.add(new int[]{x,y});
                    vis[x][y] = true;///2
                }
            }
        }
    }

2.3 细节处理:

不知道大家有没有注意到在模板那里,我在代码里标记了1和2,现在我要问问友友们,2处的代码能否省略?

答:不能省略。因为如果不加上代码2的话,有些节点会重复进入,导致代码超时(这个要想清楚,因为我当时没有代码2,检查代码检查半天才找到😭😭😭)。友友们在学完下面几个例题后可以去  岛屿数量 上面试一下。

如果疑惑哪个元素会被重复进入,可以看看下图(有点丑😭),蓝色元素会被两个红色元素扩散重复进入。如果加上代码 2 就不会有这种情况。

三、例题练习

3.1 例题1:图像渲染

• 题目链接:图像渲染

• 问题描述:

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

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

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

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

• 解题思路:

可以利用深搜(DFS)或者宽搜(BFS),遍历到与该点相连的所有像素相同的点,然后将其修改成指定的像素即可。因为这个可以直接在原来数组上修改,那么我们就不用创建 vis 来标记我们已经走过的路,由于本文章主要讲解 BFS 所以本题采用 BFS 来进行解决。最后一个小优化,如果要修改的值和原来的值相同,那么直接返回即可。

• 代码编写:

class Solution {
    int[] dx = {0,0,-1,1};
    int[] dy = {1,-1,0,0};
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        if(image[sr][sc] == color){//处理边界情况
            return image;
        }
        int n = image.length;
        int m = image[0].length;
        int prev = image[sr][sc];
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{sr,sc});//创建队列
        while(!queue.isEmpty()){
            int[] tmp = queue.poll();
            int i = tmp[0],j = tmp[1];
            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 < n && y >= 0 && y < m && image[x][y] == prev){
                    queue.offer(new int[]{x,y});
                }
            }
        }
        return image;
    }
}

3.2 例题2:岛屿数量

• 题目链接:岛屿数量

• 问题描述:

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

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

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

• 解题思路:

遍历整个矩阵,每次找到一块陆地的时候,岛屿数量 + 1,并且将这个陆地相连的所有陆地,全都修改,这样我们下次遍历到这里就不会影响最终的结果。当我们遍历完全部的矩阵的时候,岛屿数量也就找到了。

• 代码编写:

我们直接在原数据上修改,不用 vis 了。

class Solution {
    int[] dx = { 0, 0, 1, -1 };
    int[] dy = { 1, -1, 0, 0 };
    int n;
    int m;
    public int numIslands(char[][] grid) {
        int count = 0;// 最后统计岛屿数量
        n = grid.length;
        m = grid[0].length;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == '1') {//找到陆地
                    bfs(grid, i, j);//标记
                    count++;
                }
            }
        }
        return count;
    }

    public void bfs(char[][] grid, int i, int j) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[] { i, j });
        while (!queue.isEmpty()) {
            int[] tmp = queue.poll();
            int a = tmp[0];
            int b = tmp[1];
            grid[a][b] = '2';///1
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == '1'){
                    queue.add(new int[]{x,y});
                     grid[x][y] = '2';///2
                }
            }
        }
    }
}

如果没有代码块 2 就会出现下面这种情况:超时啦!

 

3.3 例题3:岛屿的最大面积

• 题目链接:岛屿的最大面积

• 问题描述:

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

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

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

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

• 解题思路:

遍历整个矩阵,每当遇到一块土地的时候,就用深搜或者宽搜将与这块土地相连的整个岛屿的面积计算出来。 然后在搜索得到的所有的岛屿面积求一个最大值即可。 在搜索过程中,为了防止搜到重复的土地。也可以将原始矩阵的 1 修改成 2,当然我们也可以使用 vis 数组来保存我们走过的路。

• 代码编写:

class Solution {
    int n,m;
    int[] dx = {0,0,1,-1};
    int[] dy = {1,-1,0,0};
    public int maxAreaOfIsland(int[][] grid) {
        int max = 0;
        n = grid.length;
        m = grid[0].length;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < m;j++){
                if(grid[i][j] == 1){
                    max = Math.max(bfs(grid,i,j),max);//找出最大面积
                }
            }
        }
        return max;
    }
    public int bfs(int[][] grid,int i,int j){
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{i,j});
        int count = 1;
        while(!queue.isEmpty()){
            int[] tmp = queue.poll();
            int a = tmp[0],b = tmp[1];
            grid[a][b] = 2;
            for(int k = 0;k < 4;k++){
                int x = a + dx[k];
                int y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1){
                    count++;
                    queue.offer(new int[]{x,y});
                    grid[x][y] = 2;//直接修改原数组的值即可。
                }
            }
        }
        return count;//返回岛屿的数量
    }
}

3.4 例题4:被围绕的区域

• 题目链接:被围绕的区域

• 问题描述:

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

• 解题思路:

我们可以发现直接做难度还是挺大的,要处理的边界和各种条件还是比较多的,这里我们采用一种正难则反的思路来解决这道问题。

1. 先处理边界上的 O 区域,因为这个 O 一定不会是被围绕的,所以遍历边界来一次搜索即可。

2. 扫描矩阵,进行还原。

这题我们采用 vis 来标记我们走过的路。

• 代码编写:

class Solution {
    boolean[][] vis;
    int[] dx = {0,0,1,-1};
    int[] dy = {1,-1,0,0};
    int n,m;
    public void solve(char[][] board) {
        n = board.length;m = board[0].length;
        vis = new boolean[n][m];
        //遍历边界
        for(int i = 0;i < m;i++){
            //第一行
            if(board[0][i] == 'O'){
                bfs(board,0,i);
            }
            //最后一行
            if(board[n - 1][i] == 'O'){
                bfs(board,n - 1,i);
            }
        }
        for(int i = 0;i < n;i++){
            //第一列
            if(board[i][0] == 'O'){
                bfs(board,i,0);
            }
            //最后一列
            if(board[i][m - 1] == 'O'){
                bfs(board,i,m - 1);
            }
        }
        //还原矩阵
        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 bfs(char[][] board,int i,int j){
        vis[i][j] = true;
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{i,j});
        while(!queue.isEmpty()){
            int[] tmp = queue.poll();
            int a = tmp[0];
            int b = tmp[1];
            for(int k = 0;k < 4;k++){
                int x = a + dx[k];
                int y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && board[x][y] == 'O' && !vis[x][y]){
                    queue.offer(new int[]{x,y});
                    vis[x][y] = true;
                }
            }
        }
    }
}

• 总结:BFS 来解决 FloodFill 类问题的模板是比较固定的,希望友友们要掌握好,因为我们后续还要利用 BFS 来解决最短路问题和拓扑排序。算法模板里面的细节处理一定要想清楚,其他的其实和之前 DFS 解决这类问题是一样的。

结语:

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

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

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

相关文章

【网络安全产品互联互通 告警信息资产信息】相关思维导图

近日&#xff0c;在某客户安全建设项目中&#xff0c;涉及安全告警事件的梳理上报。在整理及学习中发现最近&#xff08;以19年等保2.0为参考分隔“最近”&#xff09;发布的可参考标准&#xff0c;因此做了思维导图的整理。 PS&#xff1a;标准中存在引用的情况&#xff0c;过…

linux上用Jmter进行压测

在上一篇中安装好了Jmeter环境&#xff0c;在这一篇中将主要分享如何使用jmeter在linux中进行单机压测。 1.项目部署 在这里我们先简单部署一下测试环境&#xff0c;所用到的项目环境是个jar包&#xff0c;先在linux上home目录下新建app目录&#xff0c;然后通过rz命令将项目ja…

Processor System Reset IP核配置详解

本文描述了如何使用Xilinx的Vivado Design Suite环境中的工具来定制和生成 Processor System Reset IP 核。Vivado Design Suite是一个强大的FPGA设计和开发环境&#xff0c;它允许用户定制和配置各种IP核以适应他们的特定设计需求。 以下是针对如何定制IP核的步骤的简要概述&…

c#教程——索引器

前言&#xff1a; 索引器&#xff08;Indexer&#xff09;可以像操作数组一样来访问对象的元素。它允许你使用索引来访问对象中的元素&#xff0c;就像使用数组索引一样。在C#中&#xff0c;索引器的定义方式类似于属性&#xff0c;但具有类似数组的访问方式。 索引器&#x…

山东齐鲁文化名人颜廷利:朱郭有文才,曲高‘菏’寡星光路

山东齐鲁文化名人颜廷利教授表示&#xff0c;朱郭&#xff08;谐音‘祖国’&#xff09;有文才&#xff0c;《曲高‘菏’寡》星光路… 山东菏泽歌手朱之文在2011年凭借一首《滚滚长江东逝水》一夜成名&#xff0c; 十多年之后的今天&#xff0c;菏泽市网络红人郭有才靠一首《诺…

EXECL小技巧

一、批量给某列添加单引号或者双引号 如下&#xff1a;D2列为需要添加引号的列&#xff0c;效果如下图 1.双引号 """"&D2&"""" 2.双引号后增加逗号 """"&D2&""""&&quo…

React脚手架,配置环境变量(生产模式,开发模式)

项目搭建方式&#xff1a;react脚手架(create-react-app) 1. 下载依赖&#xff1a; npm install dotenv npm install dotenv-expandnpm install dotenv-cli -S 2.配置环境变量&#xff1a; 项目根部录下创建文件.env .env.pro .env.dev 配置package.json - scripts…

Golang | Leetcode Golang题解之第85题最大矩形

题目&#xff1a; 题解&#xff1a; func maximalRectangle(matrix [][]byte) (ans int) {if len(matrix) 0 {return}m, n : len(matrix), len(matrix[0])left : make([][]int, m)for i, row : range matrix {left[i] make([]int, n)for j, v : range row {if v 0 {continu…

Chromium 调试指南2024 Windows11篇-断点调试入门(九)

1. 断点调试入门&#xff1a;认识调试界面 断点调试是开发者在解决程序问题时常用的一种调试方法&#xff0c;通过在代码中设置断点&#xff0c;可以暂停程序的执行并查看程序内部状态&#xff0c;帮助定位和解决问题。本文将介绍断点调试的基本界面和功能&#xff0c;帮助开发…

算法课程笔记——路径相关树形DP

算法课程笔记——路径相关树形DP #include<bits/stdc.h>usingnamespacestd; usingLL longlong; constintN 2005; vector<int>e[N],t; structasdf{vector<int> vec; LL val; }; vector<asdf>w[N]; LL dp[N]; intn,m,k,dep[N]{1},f[N]; voiddfs(in…

【ubuntu20.04运行python文件时,报错No module named ‘rospkg’】

**问题原因&#xff1a;**一般来说&#xff0c;并不是真的缺少rospkg&#xff0c;而是系统中存在多个python版本导致的混乱 检查python版本 Ubuntu20.04 —— pyhon3.8 sudo apt-get install python3.8最新版本&#xff0c;如下图所示 查看python3.8的位置 whereis python…

【Redis】Redis 主从集群(一)

为了避免 Redis 的单点故障问题&#xff0c;可以搭建一个 Redis 集群&#xff0c;将数据备份到集群中的其它节点上。若一个 Redis 节点宕机&#xff0c;则由集群中的其它节点顶上 1.主从集群搭建 Redis 的主从集群是一个“一主多从”的读写分离集群。集群中的 Master 节点负责…

OBS插件--源录制

源录制 将应用这个滤镜的源录制成视频保存下来&#xff0c;可以选择音轨&#xff0c;也可以针对应用此滤镜的源单独的推流等。 如果在直播或录制视频的过程中场景里面布置了多个源&#xff0c;而只想保存其中一个源的视频或音频这个插件非常使用。 下面截图演示下操作步骤&a…

03-数据结构(一)

链接&#xff1a;C# 数据结构_哔哩哔哩_bilibili https://www.bilibili.com/video/BV1a541147Nk/?spm_id_from333.337.search-card.all.click&vd_source6eb7d966aa03ff5cb02b63725f651e68 链接&#xff1a;使用 C#.Net 学习掌握数据结构 (更新中)_哔哩哔哩_bilibili 一…

企业安全必备利器:专业级加密软件介绍

随着信息技术的迅猛发展&#xff0c;数据安全问题日益凸显&#xff0c;专业级加密软件应运而生&#xff0c;成为保护数据安全的重要工具。本文将对专业级加密软件进行概述&#xff0c;分析其特点、应用场景及分享。 一、专业级加密软件概述 专业级加密软件是指那些采用高级加密…

Spring Boot集成Druid快速入门Demo

1.什么是Druid&#xff1f; Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生&#xff0c;内置强大的监控功能&#xff0c;监控特性不影响性能。功能强大&#xff0c;能防SQL注入&#xff0c;内置Loging能诊断Hack应用行为。 2.mysql环境搭建 第一个mysql数…

Java线程池:当核心线程数为 0 时,任务来了的执行流程

先说结论&#xff1a;创建一个临时线程直接执行 ThreadPoolExecutor.excute() public void execute(Runnable command) {if (command null)throw new NullPointerException();int c ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true)) retu…

石墨烯材料商汉烯科技授权世强硬创,代理产品具备高导热/导电特点

近日&#xff0c;武汉汉烯科技有限公司&#xff08;下称“汉烯科技”&#xff0c;英文&#xff1a;HANXI TECH&#xff09;与世强先进&#xff08;深圳&#xff09;科技股份有限公司&#xff08;下称“世强先进”&#xff09;达成授权代理合作&#xff0c;面向锂电新能源、电子…

Node.js初步学习

1.什么是Node.js Node.js是一个跨平台Javascript运行环境&#xff0c;使开发者可以搭建服务器端的Javascript应用程序。 编写后端程序&#xff0c;提供网页资源浏览功能等等&#xff1b; 前端工程化&#xff1a;为后续学习vue和react等框架做铺垫&#xff1b;前端工程化是指…

海思Hi3065H 200MHz 高性能 RISCV32 A² MCU

这是一款海思自研的RISCV32内核的高性能实时控制专用MCU&#xff0c; 具有高性能、高集成度、高可靠性、易开发的特点&#xff0c;同时还有嵌入式AI能力。 CPU • RISC-V200MHzFPU 存储 • Up to 152KB Code Flash • 8KB Data Flash • 16KB SRAM 个人认为这是MCU梯队非常…