《LeetCode 733 图像渲染 FloodFill BFS解法》

一.题目

733. 图像渲染 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

本题除了用 DFS 实现,同样可以采用 BFS(广度优先搜索) 来完成图像渲染。

  • 从起点 (sr, sc) 开始,将其颜色改为 color,并记录原始颜色。

  • 使用一个队列,将起点入队。

  • 当队列不为空时,取出队头元素,检查它的 四个方向(上、下、左、右)的邻居格子。

  • 若邻居格子 在边界内颜色等于原始颜色尚未被访问 ,则将其颜色改为 color,并加入队列。

  • 重复此过程,直到队列为空。

三.代码演示

cpp 复制代码
class Solution
{
public:
    int bx[4] = {0,0,-1,1};
    int by[4] = {1,-1,0,0};
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color)
    {
        int prev = image[sr][sc];//获取一开始要渲染的值
        //如果渲染的值和新渲染值相同那么直接返回
        if(prev == color) return image;
        int row = image.size();//行
        int col = image[0].size();//列
        queue<pair<int,int>> q;//队列存储的是坐标
        q.push({sr,sc});
        
        while(q.size())
        {
            auto& [a,b] = q.front();//[a,b]直接获取q存储的坐标,auto会自动符合类型
            q.pop();
            image[a][b] = color;//给它渲染
            for(int k = 0;k < 4;k++)
            {
                int x = a + bx[k],y = b + by[k];
                if(x >= 0 && y >= 0 && x < row && y < col && image[x][y] == prev)
                {
                    q.push({x,y});
                }
            }
        }
        return image;

    }
};

四.代码讲解

一、方向数组与变量定义
  • bx[4]by[4]:表示上、下、左、右四个方向的偏移量。

    • {0,0,-1,1} 分别对应右、左、上、下(顺序不重要,只要四个方向覆盖即可)。
  • prev:记录起点像素的原始颜色,用于判断相邻格子是否属于同一连通区域。

  • rowcol:分别记录图像的行数和列数,用于边界检查。

  • q :队列,存储待处理的像素坐标 (x, y),用于实现广度优先搜索。

二、主函数 floodFill
  1. 获取原始颜色int prev = image[sr][sc];

  2. 提前返回 :如果 prev == color,说明新颜色与原始颜色相同,无需任何操作,直接返回原图。

  3. 获取图像尺寸row = image.size(); col = image[0].size();

  4. 初始化队列 :将起点 (sr, sc) 入队。

  5. BFS 循环:当队列不为空时,重复以下步骤:

    • 取出队头坐标 (a, b),弹出队列。

    • 将当前像素颜色改为 color

    • 遍历四个方向,计算新坐标 (x, y)

    • 若新坐标在边界内且其颜色等于原始颜色 prev,则将其入队(等待后续处理)。

  6. 返回结果:所有连通区域处理完毕后,返回修改后的图像。

三、BFS 过程细节
  • 队列的 FIFO 特性:保证了按层扩散,但本题不关心顺序,只需全部遍历即可。

  • 入队时机 :在检查到邻居格子颜色等于 prev 时立即入队,避免重复检查。

  • 颜色修改时机 :在从队列取出节点时修改,也可以入队前修改,但当前代码在取出时修改是安全的,因为入队前没有修改,可能会重复入队同一格子?实际上,由于入队前并未修改颜色,同一个格子可能被多次加入队列(因为多个邻居可能都指向它)。但这里在入队前没有检查该格子是否已被处理,所以会导致重复入队,造成大量冗余操作。 注意 :当前代码存在重复入队 的问题:一个格子可能被多个方向同时发现并加入队列,但由于未标记已处理,它会被多次入队。虽然最终结果正确,但效率会降低。更优的做法是在入队前先修改颜色或使用 visited 数组标记,避免重复入队。

四、关键细节
  • 提前返回优化:若新颜色与原始颜色相同,直接返回原图,避免不必要的遍历。

  • 边界检查 :每次生成邻居坐标后,必须检查其是否在 [0, row)[0, col) 范围内。

  • 颜色比较 :判断邻居颜色是否等于 prev,而不是等于 color,因为尚未修改的格子颜色才是原始颜色。

  • 队列元素类型 :使用 pair<int,int> 存储坐标,C++ 中可以用 {x, y} 构造,auto& [a,b] 结构绑定简化代码。

五、流程图