leetcode
leetcode 601 ~ 650
图像渲染

图像渲染

难度:

标签:

题目描述

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

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

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

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

 

示例 1:

输入: image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析: 在图像的正中间,(坐标(sr,sc)=(1,1)),在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。

示例 2:

输入: image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, newColor = 2
输出: [[2,2,2],[2,2,2]]

 

提示:

  • m == image.length
  • n == image[i].length
  • 1 <= m, n <= 50
  • 0 <= image[i][j], newColor < 216
  • 0 <= sr < m
  • 0 <= sc < n

代码结果

运行时间: 19 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 获取初始像素的颜色 oldColor。
 * 2. 如果 oldColor 与 newColor 相同,直接返回原图像。
 * 3. 使用深度优先搜索(DFS)从初始像素开始上色,
 *    每次递归处理上下左右四个方向的像素。
 * 使用 Java Stream API 的方式实现较为复杂,不适合处理这种需要递归的图像处理问题。
 */
import java.util.stream.IntStream;
public class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        int oldColor = image[sr][sc];
        if (oldColor != newColor) {
            fill(image, sr, sc, oldColor, newColor);
        }
        return image;
    }
 
    private void fill(int[][] image, int sr, int sc, int oldColor, int newColor) {
        if (sr < 0 || sr >= image.length || sc < 0 || sc >= image[0].length) return;
        if (image[sr][sc] != oldColor) return;
        image[sr][sc] = newColor;
        IntStream.of(-1, 1).forEach(i -> {
            fill(image, sr + i, sc, oldColor, newColor); // 上下
            fill(image, sr, sc + i, oldColor, newColor); // 左右
        });
    }
}

解释

方法:

该题解使用深度优先搜索(DFS)的思路,具体步骤如下: 1. 定义方向数组 directions,表示上下左右四个方向。 2. 记录初始点的颜色为 changed_color。 3. 如果初始点的颜色与新颜色相同,直接返回原图像。 4. 将初始点坐标压入栈 stack 中。 5. 当栈不为空时,循环执行以下操作: - 弹出栈顶元素 curr,获取当前点的坐标 (row, col)。 - 将当前点的颜色更改为新颜色。 - 遍历四个方向: - 计算新坐标 (newrow, newcol)。 - 如果新坐标在图像范围内且颜色与初始点相同,将新坐标压入栈中。 6. 返回更改后的图像。

时间复杂度:

O(m*n)

空间复杂度:

O(m*n)

代码细节讲解

🦆
为什么在这个算法中选择使用深度优先搜索(DFS)而不是广度优先搜索(BFS)?
深度优先搜索(DFS)和广度优先搜索(BFS)都可以用来解决图像渲染问题,但DFS在实现上通常更简洁。在DFS中使用栈来存储待处理的节点,而在BFS中则需要使用队列。在某些情况下,DFS的递归或栈的使用可以更快地到达远端节点,尤其是在需要涂色的区域较大或者形状复杂时。此外,DFS的空间复杂度在最坏情况下与BFS相同,都是O(n),但在平均情况下,DFS因为早日达到深层节点而可能使用更少的空间。因此,选择DFS还是BFS更多基于实现的偏好和特定问题的性质。
🦆
在判断新坐标是否在图像范围内时,代码中的检查逻辑是否有重复计算的可能,能否优化?
在提供的代码中,每次遍历新的方向都会独立检查新坐标是否在图像的有效范围内,这个过程中确实存在重复计算。例如,对于每一个方向,都会重新计算 `newrow in range(len(image))` 和 `newcol in range(len(image[newrow]))`,这些操作可以优化。一种方法是先计算图像的行数和列数,将其存储为常量,然后直接使用这些常量来检查坐标的有效性,从而避免在每次迭代中重新计算图像的维度。
🦆
为何在栈为空前持续处理,而不是检查某种条件后退出循环?
在这个DFS实现中,栈用于存储每个需要处理的像素点。只有栈为空时,算法才会结束,这是因为栈为空意味着没有更多的相邻像素需要变色。这种处理确保了所有与初始点颜色相同且相邻的像素都被遍历并着色。如果提前退出循环,可能会导致某些应该被着色的区域未被处理,从而得到错误的结果。因此,持续处理直到栈为空是确保正确性的必需步骤。
🦆
代码中直接修改了输入的`image`数组,这种做法是否安全,或者是否有不修改原输入的方案?
直接修改输入的`image`数组可以节省空间和时间,因为不需要创建和维护一个额外的数组副本。然而,这种做法可能不安全或不可取,特别是在需要保持原始数据不变的情况下。如果不希望修改原始输入,可以先复制一份`image`数组,然后在这个副本上进行操作。这样做虽然增加了空间复杂度,但保证了原始数据的安全性。

相关问题

岛屿的周长

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。

网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

 

示例 1:

输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
解释:它的周长是上面图片中的 16 个黄色的边

示例 2:

输入:grid = [[1]]
输出:4

示例 3:

输入:grid = [[1,0]]
输出:4

 

提示:

  • row == grid.length
  • col == grid[i].length
  • 1 <= row, col <= 100
  • grid[i][j]01