LeetCode 面试题 08.10. 颜色填充
题目描述

题意分析
把起点所在的同色四连通区域全部改为新颜色。区域内的格子必须能沿上、下、左、右相邻路径到达起点,并且原颜色与起点相同;仅仅颜色相同但不连通的格子不改变。
解法:从起点扩散并用新颜色标记
核心思路
[!blue]
先保存起点的原颜色
oc,此后所有进入条件都与这个固定颜色比较。DFS 从起点出发,越界或颜色不同就停止;符合条件的格子先改为新颜色,再递归检查它的四个邻居。当新旧颜色不同时,改色同时起到访问标记的作用:再次从邻居走回这个格子时,它已经不等于
oc,会立即返回。因此无需额外的访问数组,但必须在递归邻居之前改色,才能阻断相邻格子之间的来回访问。新颜色恰好等于原颜色时,写回同样的值无法表示“已访问”。代码额外检查当前格是否已经等于新颜色,使初始 DFS 直接返回;图像本来就是期望颜色,不需要继续扩散。
DFS 只沿原色格子的四邻边扩展,所以不会离开起点的同色区域;对区域内任一格,沿着它到起点的原色路径逐步扩展又一定能到达它。每个格子只在第一次进入时展开邻居,因而整个区域恰好被填充,其他位置保持不变。
解题步骤
- 在任何写入前,保存起点原颜色和目标新颜色。
- 从起点调用 DFS,先判断坐标范围,再读取颜色判断是否可以进入。
- 当前颜色不等于原色,或已经等于新色时直接返回。
- 将当前格改为新色,再递归四个相邻位置。
- 搜索结束后返回原图像数组,修改已经在数组中完成。
方向数组
[-1, 0, 1, 0, -1]每两个相邻值组成一个行列偏移,依次表示上、右、下、左,不包含对角方向。
代码实现
class Solution {
private int[] dirs = {
-1,
0,
1,
0,
-1
};
private int[][] image;
private int nc;
private int oc;
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
nc = newColor;
// 必须在任何写入之前取出起点原色。
oc = image[sr][sc];
this.image = image;
dfs(sr, sc);
return image;
}
private void dfs(int i, int j) {
// image[i][j] == nc 专门用于新旧同色时阻断无限递归。
if (i < 0
|| i >= image.length
|| j < 0
|| j >= image[0].length
|| image[i][j] != oc
|| image[i][j] == nc) {
return;
}
image[i][j] = nc;
for (int k = 0; k < 4; ++k) {
dfs(i + dirs[k], j + dirs[k + 1]);
}
}
}
func floodFill(image [][]int, sr int, sc int, newColor int) [][]int {
// 必须在任何写入之前取出起点原色。
oc := image[sr][sc]
m, n := len(image), len(image[0])
dirs := []int{
-1,
0,
1,
0,
-1,
}
var dfs func(i, j int)
dfs = func(i, j int) {
// image[i][j] == newColor 专门用于新旧同色时阻断无限递归。
if i < 0 || i >= m || j < 0 || j >= n || image[i][j] != oc || image[i][j] == newColor {
return
}
image[i][j] = newColor
for k := 0; k < 4; k++ {
dfs(i+dirs[k], j+dirs[k+1])
}
}
dfs(sr, sc)
return image
}
复杂度分析
- 时间复杂度:最坏为 $O(mn)$,其中 $m$、$n$ 是图像行列数。每个被填充格子只展开一次,每次检查四个邻居。
- 空间复杂度:最坏为 $O(mn)$,连通区域可能让递归路径经过所有格子;改色标记本身不需要额外访问数组。
关键点总结
[!green]
- 始终用起点最初的颜色判断是否属于目标区域,不能在改色后重新取原色。
- 新旧颜色不同时,改色就是访问标记;同色时必须直接停止。
- 先改色再扩散,使每个合法格子只展开一次。
易错点总结
[!yellow]
- 在检查坐标之前读取数组,越界邻居会触发非法访问。
- 先递归邻居再改色,可能让尚未标记的相邻格子互相递归。
- 忽略新旧颜色相同的情况,会失去改色标记的阻断作用。
- 不能把对角相邻算作连通,也不能仅凭颜色相同就修改图中所有格子。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 200. 岛屿数量 | 中等 | 同样遍历四连通分量并标记访问,原题要统计全部岛屿,本题只从一个起点扩散。 |
| 695. 岛屿的最大面积 | 中等 | 同样对一个连通区域做 DFS,原题累计面积,本题写入新颜色。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!