搜索题目:边界着色

文章目录

题目

标题和出处

标题:边界着色

出处:1034. 边界着色

难度

5 级

题目描述

要求

给定一个 m × n \texttt{m} \times \texttt{n} m×n 的整数矩阵 grid \texttt{grid} grid,以及三个整数 row \texttt{row} row、 col \texttt{col} col 和 color \texttt{color} color。网格中的每个值表示该位置处的网格块的颜色。

如果两个网格块颜色相同且在四个方向上相邻,那么这两个网格块属于同一连通分量

连通分量的边界是指连通分量中的在四个方向上与不属于同一连通分量的网格块相邻的网格块,或者在网格的边界上的网格块。

使用 color \texttt{color} color 为所有包含网格块 grid[row][col] \texttt{grid[row][col]} grid[row][col] 的连通分量边界着色。

返回最终的网格。

示例

示例 1:

输入: grid = [[1,1],[1,2]], row = 0, col = 0, color = 3 \texttt{grid = [[1,1],[1,2]], row = 0, col = 0, color = 3} grid = [[1,1],[1,2]], row = 0, col = 0, color = 3

输出: [[3,3],[3,2]] \texttt{[[3,3],[3,2]]} [[3,3],[3,2]]

示例 2:

输入: grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3 \texttt{grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3} grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3

输出: [[1,3,3],[2,3,3]] \texttt{[[1,3,3],[2,3,3]]} [[1,3,3],[2,3,3]]

示例 3:

输入: grid = [[1,1,1],[1,1,1],[1,1,1]], row = 1, col = 1, color = 2 \texttt{grid = [[1,1,1],[1,1,1],[1,1,1]], row = 1, col = 1, color = 2} grid = [[1,1,1],[1,1,1],[1,1,1]], row = 1, col = 1, color = 2

输出: [[2,2,2],[2,1,2],[2,2,2]] \texttt{[[2,2,2],[2,1,2],[2,2,2]]} [[2,2,2],[2,1,2],[2,2,2]]

数据范围

  • m = grid.length \texttt{m} = \texttt{grid.length} m=grid.length
  • n = grid[i].length \texttt{n} = \texttt{grid[i].length} n=grid[i].length
  • 1 ≤ m, n ≤ 50 \texttt{1} \le \texttt{m, n} \le \texttt{50} 1≤m, n≤50
  • 1 ≤ grid[i][j], color ≤ 1000 \texttt{1} \le \texttt{grid[i][j], color} \le \texttt{1000} 1≤grid[i][j], color≤1000
  • 0 ≤ row < m \texttt{0} \le \texttt{row} < \texttt{m} 0≤row<m
  • 0 ≤ col < n \texttt{0} \le \texttt{col} < \texttt{n} 0≤col<n

解法一

思路和算法

首先获得 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的原始颜色 originalColor \textit{originalColor} originalColor,如果 originalColor = color \textit{originalColor} = \textit{color} originalColor=color,则原始颜色与新颜色相同,不需要对任何网格块着色,直接返回 grid \textit{grid} grid。

如果 originalColor ≠ color \textit{originalColor} \ne \textit{color} originalColor=color,则为了将包含 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的连通分量的边界着色,需要从 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 开始遍历连通分量中的每个网格块,寻找连通分量的边界。

可以使用广度优先搜索寻找连通分量的边界。

广度优先搜索需要使用列表记录连通分量的边界,并使用与网格相同大小的二维数组记录每个网格块是否被访问过,初始时只有 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的状态是已访问,其余网格块的状态都是未访问。对于连通分量中的每个网格块,考虑与当前网格块在四个方向上相邻的网格块,执行如下操作。

  1. 如果相邻的网格块的颜色是 originalColor \textit{originalColor} originalColor,则需要继续访问该相邻的网格块。

  2. 如果存在至少一个方向,该方向的相邻的网格块的颜色不是 originalColor \textit{originalColor} originalColor 或相邻的网格块不存在,则当前网格块是连通分量的边界,将当前网格块添加到连通分量的边界列表中。

遍历结束之后,得到包含 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的连通分量的全部边界,将边界的颜色改为 color \textit{color} color。

需要注意的是,由于判断一个网格块是否属于当前连通分量以及是否为边界需要考虑相关网格块的原始颜色,因此不能在遍历过程中将连通分量的边界着色,必须在遍历结束之后将连通分量的边界着色。

代码

java 复制代码
class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    public int[][] colorBorder(int[][] grid, int row, int col, int color) {
        int originalColor = grid[row][col];
        if (originalColor == color) {
            return grid;
        }
        List<int[]> borders = new ArrayList<int[]>();
        int m = grid.length, n = grid[0].length;
        boolean[][] visited = new boolean[m][n];
        visited[row][col] = true;
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(new int[]{row, col});
        while (!queue.isEmpty()) {
            int[] square = queue.poll();
            int currRow = square[0], currCol = square[1];
            boolean isBorder = false;
            for (int[] dir : dirs) {
                int nextRow = currRow + dir[0], nextCol = currCol + dir[1];
                if (nextRow >= 0 && nextRow < m && nextCol >= 0 && nextCol < n && grid[nextRow][nextCol] == originalColor) {
                    if (!visited[nextRow][nextCol]) {
                        visited[nextRow][nextCol] = true;
                        queue.offer(new int[]{nextRow, nextCol});
                    }
                } else {
                    isBorder = true;
                }
            }
            if (isBorder) {
                borders.add(square);
            }
        }
        for (int[] border : borders) {
            grid[border[0]][border[1]] = color;
        }
        return grid;
    }
}

复杂度分析

  • 时间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。广度优先搜索最多访问每个网格块一次。

  • 空间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。记录连通分量边界的列表、记录每个网格块是否被访问过的二维数组和队列需要 O ( m n ) O(mn) O(mn) 的空间。

解法二

思路和算法

如果 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的原始颜色 originalColor \textit{originalColor} originalColor 与新颜色 color \textit{color} color 不同,也可以使用深度优先搜索寻找连通分量的边界。

深度优先搜索需要使用列表记录连通分量的边界,并使用与网格相同大小的二维数组记录每个网格块是否被访问过,初始时只有 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的状态是已访问,其余网格块的状态都是未访问。对于连通分量中的每个网格块,考虑与当前网格块在四个方向上相邻的网格块,执行如下操作。

  1. 如果相邻的网格块的颜色是 originalColor \textit{originalColor} originalColor,则需要继续访问该相邻的网格块。

  2. 如果存在至少一个方向,该方向的相邻的网格块的颜色不是 originalColor \textit{originalColor} originalColor 或相邻的网格块不存在,则当前网格块是连通分量的边界,将当前网格块添加到连通分量的边界列表中。

遍历结束之后,得到包含 grid [ row ] [ col ] \textit{grid}[\textit{row}][\textit{col}] grid[row][col] 的连通分量的全部边界,将边界的颜色改为 color \textit{color} color。

需要注意的是,由于判断一个网格块是否属于当前连通分量以及是否为边界需要考虑相关网格块的原始颜色,因此不能在遍历过程中将连通分量的边界着色,必须在遍历结束之后将连通分量的边界着色。

代码

java 复制代码
class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    List<int[]> borders = new ArrayList<int[]>();
    int m, n;
    int[][] grid;
    boolean[][] visited;
    int originalColor;
    int color;

    public int[][] colorBorder(int[][] grid, int row, int col, int color) {
        originalColor = grid[row][col];
        if (originalColor == color) {
            return grid;
        }
        this.m = grid.length;
        this.n = grid[0].length;
        this.grid = grid;
        this.visited = new boolean[m][n];
        this.color = color;
        dfs(row, col);
        for (int[] border : borders) {
            grid[border[0]][border[1]] = color;
        }
        return grid;
    }

    public void dfs(int currRow, int currCol) {
        visited[currRow][currCol] = true;
        boolean isBorder = false;
        for (int[] dir : dirs) {
            int nextRow = currRow + dir[0], nextCol = currCol + dir[1];
            if (nextRow >= 0 && nextRow < m && nextCol >= 0 && nextCol < n && grid[nextRow][nextCol] == originalColor) {
                if (!visited[nextRow][nextCol]) {
                    dfs(nextRow, nextCol);
                }
            } else {
                isBorder = true;
            }
        }
        if (isBorder) {
            borders.add(new int[]{currRow, currCol});
        }
    }
}

复杂度分析

  • 时间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。深度优先搜索最多访问每个网格块一次。

  • 空间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。记录连通分量边界的列表、记录每个网格块是否被访问过的二维数组和递归调用栈需要 O ( m n ) O(mn) O(mn) 的空间。

相关推荐
伟大的车尔尼6 天前
搜索题目:二进制矩阵中的最短路径
广度优先搜索
伟大的车尔尼8 天前
搜索题目:被围绕的区域
并查集·深度优先搜索·广度优先搜索
Tisfy9 天前
LeetCode 1722.执行交换操作后的最小汉明距离:连通图
算法·leetcode·dfs·题解·深度优先搜索·连通图
伟大的车尔尼13 天前
搜索题目:地图分析
动态规划·广度优先搜索
伟大的车尔尼15 天前
搜索题目:腐烂的橘子
广度优先搜索
伟大的车尔尼15 天前
搜索题目:01 矩阵
动态规划·广度优先搜索
伟大的车尔尼20 天前
搜索题目:图像渲染
并查集·深度优先搜索·广度优先搜索
伟大的车尔尼22 天前
搜索题目:甲板上的战舰
并查集·深度优先搜索·广度优先搜索
伟大的车尔尼1 个月前
广度优先搜索和深度优先搜索的概念
数据结构·算法·并查集·深度优先搜索·广度优先搜索