跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

BFS 解决 FloodFill 算法:从图像渲染到岛屿问题实战

BFS 算法在 FloodFill 场景下的应用。涵盖图像渲染、岛屿数量及最大面积、被围绕区域四个经典 LeetCode 题目。通过队列实现广度优先搜索,标记访问状态,处理连通性问题。重点在于边界检查、颜色/字符匹配及避免重复遍历。Java 实现示例展示如何优化时空复杂度,适用于网格类图论问题。

莫名其妙发布于 2026/3/27更新于 2026/7/2333 浏览
BFS 解决 FloodFill 算法:从图像渲染到岛屿问题实战

FloodFill 算法的核心思想其实很直观,就像洪水蔓延一样,从一个点出发,向四周扩散,把连通且满足条件的区域全部覆盖。在图论和网格问题中,这通常对应着广度优先搜索(BFS)或深度优先搜索(DFS)。

733. 图像渲染

这道题是 FloodFill 最经典的入门应用。给定一个二维数组表示的图像,以及起始坐标和新颜色,要求将与起始点相连且颜色相同的像素全部修改为新颜色。

思路解析

本质上就是遍历所有与起点相连的同色像素。我们可以利用队列来存储待处理的坐标。每次取出一个坐标,检查其上下左右四个方向,如果邻居合法、颜色相同且未被处理过,就将其加入队列并修改颜色。

这里有个细节要注意:如果起始点的颜色本身就是目标颜色,直接返回原数组即可,避免无效操作。另外,边界检查必不可少,防止数组越界。

// 时间复杂度:O(N),空间复杂度:O(N)
class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        // 记录开始颜色
        int pre = image[sr][sc];
        // 如果初始颜色就是目标颜色,无需处理
        if (pre == color) return image;

        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{sr, sc});

        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int x = cur[0];
            int y = cur[1];

            // 检查上下左右四个方向
            int[] dx = {0, 0, 1, -1};
            int[] dy = {1, -1, 0, 0};

            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                // 下标合法且颜色相同,进行传染
                if (nx >= 0 && nx < image.length && 
                    ny >= 0 && ny < image[0].length && 
                    pre == image[nx][ny]) {
                    image[nx][ny] = color;
                    queue.add(new int[]{nx, ny});
                }
            }
        }
        return image;
    }
}

200. 岛屿数量

题目给出了一个由 '0'(水)和 '1'(陆地)组成的二维字符数组,要求计算岛屿的数量。岛屿被水平或垂直方向的 '1' 连接而成。

思路解析

我们需要遍历整个网格,每遇到一个未访问过的 '1',就说明发现了一个新岛屿。此时启动一次 BFS,将这块岛屿上所有相连的 '1' 都标记为已访问,这样后续遍历时就不会重复计数了。

为了节省空间,我们通常使用一个 visited 布尔数组来记录状态,或者直接在原数组上将访问过的 '1' 改为 '0'。

// 时间复杂度:O(M*N),空间复杂度:O(M*N)
class Solution {
    int[] dx = {0, 0, 1, -1};
    int[] dy = {1, -1, 0, 0};
    boolean[][] vis;

    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) return 0;
        int m = grid.length;
        int n = grid[0].length;
        vis = new boolean[m][n];
        int ret = 0;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 找到第一个未访问的 '1',作为'登陆点'
                if (grid[i][j] == '1' && !vis[i][j]) {
                    bfs(grid, i, j, m, n);
                    ret++;
                }
            }
        }
        return ret;
    }

    private void bfs(char[][] grid, int x, int y, int m, int n) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{x, y});
        vis[x][y] = true;

        while (!queue.isEmpty()) {
            int[] arr = queue.poll();
            for (int i = 0; i < 4; i++) {
                int nx = arr[0] + dx[i];
                int ny = arr[1] + dy[i];
                // 下标合法,字符为 '1',且并没有被访问
                if (nx >= 0 && nx < m && ny >= 0 && ny < n &&
                    grid[nx][ny] == '1' && !vis[nx][ny]) {
                    vis[nx][ny] = true;
                    queue.add(new int[]{nx, ny});
                }
            }
        }
    }
}

695. 岛屿的最大面积

这道题和上一题非常相似,区别在于需要计算每个岛屿包含的格子数,并返回最大值。

思路解析

在 BFS 遍历过程中,每弹出一个节点,面积计数器加一。遍历完当前岛屿后,更新全局最大面积即可。

// 时间复杂度:O(M*N),空间复杂度:O(M*N)
class Solution {
    int[] dx = {0, 0, 1, -1};
    int[] dy = {1, -1, 0, 0};
    boolean[][] vis;

    public int maxAreaOfIsland(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        vis = new boolean[m][n];
        int maxArea = 0;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1 && !vis[i][j]) {
                    int currentArea = bfs(grid, i, j, m, n);
                    maxArea = Math.max(maxArea, currentArea);
                }
            }
        }
        return maxArea;
    }

    private int bfs(int[][] grid, int x, int y, int m, int n) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{x, y});
        vis[x][y] = true;
        int area = 0;

        while (!queue.isEmpty()) {
            int[] arr = queue.poll();
            area++;
            for (int i = 0; i < 4; i++) {
                int nx = arr[0] + dx[i];
                int ny = arr[1] + dy[i];
                if (nx >= 0 && nx < m && ny >= 0 && ny < n &&
                    grid[nx][ny] == 1 && !vis[nx][ny]) {
                    vis[nx][ny] = true;
                    queue.add(new int[]{nx, ny});
                }
            }
        }
        return area;
    }
}

130. 被围绕的区域

这道题稍微绕一点。给定一个由 'X' 和 'O' 组成的二维字符数组,要求将所有被 'X' 完全包围的 'O' 替换为 'X'。注意,边缘的 'O' 以及与边缘 'O' 相连的 'O' 不会被替换。

思路解析

与其思考哪些 'O' 会被包围,不如反过来想:哪些 'O' 是安全的?显然是那些能连接到边界的 'O'。因此,策略变为:

  1. 遍历四条边上的所有元素,如果发现 'O',就从该点开始 BFS/DFS,将所有连通的 'O' 标记为特殊状态(比如用临时字符或布尔数组)。
  2. 遍历整个矩阵,将没有被标记的 'O' 改为 'X',将标记过的恢复为 'O'(或者直接保留标记后的逻辑)。

这种逆向思维在网格问题中非常常见,能有效降低判断复杂度。

// 时间复杂度:O(M*N),空间复杂度:O(M*N)
class Solution {
    int[] dx = {0, 0, 1, -1};
    int[] dy = {1, -1, 0, 0};
    boolean[][] flag;
    int m, n;

    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        m = board.length;
        n = board[0].length;
        flag = new boolean[m][n];

        // 只遍历边缘字符元素
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 如果是边缘且为 'O',则进行宽搜标记
                if ((i == 0 || i == m - 1 || j == 0 || j == n - 1) &&
                    board[i][j] == 'O' && !flag[i][j]) {
                    bfs(board, i, j);
                }
            }
        }

        // 将被包围的字符改为 X
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O' && !flag[i][j]) {
                    board[i][j] = 'X';
                }
            }
        }
    }

    // 宽搜符合条件的不被包围字符
    private void bfs(char[][] board, int x, int y) {
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{x, y});
        flag[x][y] = true;

        while (!queue.isEmpty()) {
            int[] arr = queue.poll();
            for (int i = 0; i < 4; i++) {
                int nx = arr[0] + dx[i];
                int ny = arr[1] + dy[i];
                if (nx >= 0 && nx < m && ny >= 0 && ny < n &&
                    board[nx][ny] == 'O' && !flag[nx][ny]) {
                    queue.add(new int[]{nx, ny});
                    flag[nx][ny] = true;
                }
            }
        }
    }
}

目录

  1. 733. 图像渲染
  2. 200. 岛屿数量
  3. 695. 岛屿的最大面积
  4. 130. 被围绕的区域
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AIGC 如何改变金融业?不是所有智能化问题都要用大模型解决
  • VR、具身智能与人形机器人:通往现实世界的智能接口
  • Python 标准库与第三方库实战:日期处理、字符串操作及 Excel 应用
  • Git 基础指令与本地仓库操作指南
  • Git 仓库迁移指南:从 CODING.net 至腾讯云 CNB
  • MySQL 索引原理:B+ 树结构与实战优化
  • 马斯克xAI开源Grok-1:3140亿参数模型架构详解
  • 融合选择性卷积与残差结构的 SKResNet 架构详解
  • Java 设计模式:静态工厂方法详解
  • Python 基础语法完全指南:变量数据类型运算符与字符串
  • 国内用户如何付费升级 GitHub Copilot 专业版
  • GLM-4.7 技术解析:开源模型在编码与推理上的新突破
  • 基于 OpenClaw 快速搭建企业微信 AI 客服
  • Z 字形变换与外观数列算法解析
  • 前端文件下载实战:从原理到最佳实践
  • 大模型周报:OpenAI GPT-Next 计划及多模态技术进展
  • FPGA 实现 CAN 总线原理与 Verilog 代码详解
  • CANN Catlass 模板库核心能力与编程实战
  • 免费 Trae 编辑器体验:排队机制与工程化效率的思考
  • 借助 DeepSeek 与云算力快速搭建个人网页

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online