在问 · 算法题解

733. 图像渲染

简单图论广度优先搜索力扣原题 ↗

题目描述

输入 m x n 整数矩阵 image 表示一张图片,image[i][j] 是像素颜色。另给出整数 sr、sc 和 color,下标从 0 开始。

记起点像素 image[sr][sc] 原来的颜色为 c。从起点出发,沿上下左右四个方向走,只能经过颜色为 c 的像素。把所有能走到的像素(含起点)都改成 color。

返回修改后的图片。如果 color 与 c 相同,图片不变。

示例 1
输入:image = [[1,1,1],[1,1,0],[1,0,1]], sr = 1, sc = 1, color = 2
输出:[[2,2,2],[2,2,0],[2,0,1]]

解释:与中心相连的值为 1 的格子都变成 2;右下角的 1 只与中心斜向相邻,保持不变。

示例 2
输入:image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, color = 0
输出:[[0,0,0],[0,0,0]]

解释:新颜色与原颜色都是 0,图片不变。

数据范围

  • m == image.length
  • n == image[i].length
  • 1 <= m, n <= 50
  • 0 <= image[i][j], color < 2^16
  • 0 <= sr < m
  • 0 <= sc < n

解题思路:广度优先搜索

记下起点原来的颜色 old。如果 old 已经等于 color,直接返回,否则会无限循环。把起点染色后入队,做 BFS:每出队一个像素,检查四个方向的邻居,在界内且颜色为 old 的邻居立刻染成 color 并入队。

为什么正确

队列中的像素都已染成 color;已染色的像素不再等于 old,所以不会重复入队。

复杂度分析

时间 O(mn),每个像素最多入队一次;空间 O(mn),用于队列。

易错点

当 old == color 时必须直接返回:染色后像素仍等于 old,会被反复入队,导致死循环。另外要在入队时染色,而不是出队时,否则同一像素可能多次入队。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
        old = image[sr][sc]
        if old == color:
            return image
        m, n = len(image), len(image[0])
        image[sr][sc] = color
        queue = collections.deque([(sr, sc)])
        while queue:
            r, c = queue.popleft()
            for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
                if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == old:
                    image[nr][nc] = color
                    queue.append((nr, nc))
        return image

载入编辑器,自己跑一遍 →

其他解法

两种搜索都把每个像素处理一次,复杂度相同;广度优先用队列没有栈溢出风险,深度优先递归写法更简洁。

解法 2:深度优先搜索 时间 O(m·n),空间 O(m·n)

记下起点原色 old,若与新颜色相同直接返回。递归函数先把当前像素染成新颜色,再对四个方向中在网格内且颜色等于 old 的邻居递归。染色本身就是访问标记。

代码比广度优先搜索更短,不需要队列。最坏递归深度可达 m·n,Python 需要调高递归上限。

class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
        old = image[sr][sc]
        if old == color:
            return image
        sys.setrecursionlimit(10000)
        m, n = len(image), len(image[0])

        def dfs(r, c):
            image[r][c] = color
            for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
                if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == old:
                    dfs(nr, nc)

        dfs(sr, sc)
        return image

图论 专题的其他题目

查看 图论 全部题目 →