目录
边界着色
描述
给你一个大小为 m x n 的整数矩阵 grid ,表示一个网格。另给你三个整数 row、col 和 color 。网格中的每个值表示该位置处的网格块的颜色。
当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一 连通分量 。
连通分量的边界 是指连通分量中的所有与不在分量中的网格块相邻(四个方向上)的所有网格块,或者在网格的边界上(第一行/列或最后一行/列)的所有网格块。
请你使用指定颜色 color 为所有包含网格块 grid[row][col] 的 连通分量的边界 进行着色,并返回最终的网格 grid 。
示例 1
输入:grid = [[1,1],[1,2]], row = 0, col = 0, color = 3 输出:[[3,3],[3,2]]
示例 2
输入:grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3 输出:[[1,3,3],[2,3,3]]
示例 3
输入: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]]
提示
这题目确实比较抽象不太好理解,大概意思可以简单认为有一个矩阵,如下图所示,假设我们给定的初始点为(2,2),即第三行第三列的位置,里面存储的是2,我们要找所有颜色为2的并与该点连通的区域即橙色区域,深橙色即为连通区域的边界,我们将这些边界赋值为传入的color,返回矩阵即可。
方法一:堆栈(迭代)
class Solution {
public int[][] colorBorder(int[][] grid, int row, int col, int color) {
Stack<int[]> stack = new Stack<>();//存放所有要访问的点
boolean[][] isVisted = new boolean[grid.length][grid[0].length];//记录当前点是否被访问过
int target = grid[row][col];//原连通分量中的值
int[][] res=new int[grid.length][grid[0].length];
for (int i = 0; i < grid.length; i++) for (int j = 0; j < grid[0].length; j++) res[i][j]=grid[i][j];//进行赋值
stack.push(new int[]{row, col});
while (!stack.isEmpty()) {
int[] pop = stack.pop();//取出当前位置
int curRow = pop[0], curCol = pop[1];
//统计出上下左右四个方向的连通分量,加入到stack中
if (curRow + 1 < grid.length && grid[curRow + 1][curCol] == target && !isVisted[curRow + 1][curCol])
stack.push(new int[]{curRow + 1, curCol});
if (curRow - 1 >= 0 && grid[curRow - 1][curCol] == target && !isVisted[curRow - 1][curCol])
stack.push(new int[]{curRow - 1, curCol});
if (curCol + 1 < grid[0].length && grid[curRow][curCol + 1] == target && !isVisted[curRow][curCol + 1])
stack.push(new int[]{curRow, curCol + 1});
if (curCol - 1 >= 0 && grid[curRow][curCol - 1] == target && !isVisted[curRow][curCol - 1])
stack.push(new int[]{curRow, curCol - 1});
//对当前连通分量进行判断是否赋值
isVisted[curRow][curCol] = true;
if (curRow == 0 || curRow == grid.length - 1 || curCol == 0 || curCol == grid[0].length - 1 ||
!(grid[curRow - 1][curCol] == target && grid[curRow + 1][curCol] == target &&
grid[curRow][curCol + 1] == target && grid[curRow][curCol - 1] == target)) {//如果是连通分量边界
res[curRow][curCol] = color;//则将该块颜色赋值
}
}
return res;
}
}
方法二:深度优先搜索(递归)
class Solution {
public int[][] colorBorder2(int[][] grid, int row, int col, int color) {
int m = grid.length, n = grid[0].length;
boolean[][] visited = new boolean[m][n];//记录当前点是否被访问过
List<int[]> borders = new ArrayList<>();//存储边界点信息
int originalColor = grid[row][col];//记录原始颜色
visited[row][col] = true;
dfs(grid, row, col, visited, borders, originalColor);//深搜
for (int i = 0; i < borders.size(); i++) {
int x = borders.get(i)[0], y = borders.get(i)[1];
grid[x][y] = color;//对所有连通分量边界赋值
}
return grid;
}
public void dfs(int[][] grid, int x, int y, boolean[][] visited, List<int[]> borders, int originalColor) {
int m = grid.length, n = grid[0].length;
boolean isBorder = false;//标识当前点是否为连通分量边界
int[][] direc = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
for (int i = 0; i < 4; i++) {
int nx = direc[i][0] + x, ny = direc[i][1] + y;
if (!(nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == originalColor)) {
isBorder = true;
} else if (!visited[nx][ny]){
visited[nx][ny] = true;
dfs(grid, nx, ny, visited, borders, originalColor);
}
}
if (isBorder) {//记录所有连通分量边界
borders.add(new int[]{x, y});
}
}
}