文章摘要:
- 本文介绍了使用深度优先搜索(DFS)实现洪水填充(floodfill)算法来解决图像渲染问题。算法从给定起始位置开始,递归搜索相邻且像素值相同的区域,并将其修改为目标颜色。关键点包括:判断起始像素与目标颜色是否相同以避免无效操作,使用全局变量简化递归参数,通过方向数组实现四向搜索,以及无需回溯和剪枝的特性。代码实现清晰展示了DFS的核心逻辑,包括边界检查、颜色判断和递归调用。该算法能有效处理二维矩阵中的连通区域填充问题。
文章目录
题目链接:733. 图像渲染
一、题目解析
首先我们介绍一下什么是 "floodfill算法"。
floodfill 算法,也称为洪水填充 算法,指的是在区域中找到性质相同的联通块,注意这里的联通块指的是上下左右相邻,斜线不能算做相邻。该算法可以使用 深度优先搜索 和 广度优先搜索 来解决,我们这里采用深度优先搜索(DFS)的策略来解决。
我们回到题目,题目给我们一个由整数组成的二维矩阵 image,其中的数字表示像素值。题目同时给出 sr、sc 和 color 分别表示起始位置 image[sr][sc] 和 目标色块。
我们需要从起始位置开始,找到所有与初始位置色块相邻的其他色块(色块相同)并将色块修改成 color。
例一:
- image = [ [ 1, 1, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ] ]
- sr = 1, sc = 1, color = 2
image 表示为如下网格:
1 |
1 |
1 |
|---|---|---|
1 |
1 |
0 |
1 |
0 | 1 |
所有红色的区域就是性质相同的联通块。
修改后的 image 网格:
2 |
2 |
2 |
|---|---|---|
2 |
2 |
0 |
2 |
0 | 1 |
例二:
- image = [ [ 0, 0, 0 ], [ 0, 0, 0 ] ]
- sr = 0, sc = 0, color = 0
0 |
0 |
0 |
|---|---|---|
0 |
0 |
0 |
0 |
0 |
0 |
这个例子中其实位置的像素值与 color 一致,无需修改直接返回即可。
二、算法原理 + 代码实现
这道题目同样是一道二维矩阵搜索类的题目,我们从起始位置开始深搜,对每一个指定位置向上下左右四个方向按照特定的条件搜索方格然后修改为 color,直到没得搜索为止。
在搜索之前先对起始位置的像素值进行判断:如果像素值与 color 相同,我们就不需要做任何改动直接返回;如果相同就先将像素值改为 color (在这之前先记录原像素值),然后从起始位置开始深搜递归。
全局变量
为了递归方便,我们将题目给出的 image 改为全局变量,同时 m 和 n 记录矩阵的大小。
然后是 originColor 用于记录起始位置的原像素值,题目给出的 color,然后是两个向量数组 dx 和 dy。
java
int[][] image;
int originColor, color, m, n;
int[] dx = {0, 0, -1, 1};
int[] dy = {-1, 1, 0, 0};
dfs 函数
函数头
dfs 函数的任务是帮助我们搜索指定位置的上下左右四个方位并且根据指定条件修改方格的像素值。
我们这里的参数是某个位置的坐标 row 和 col,函数的返回值为 void。
java
dfs(int row, int col);
函数体
我们循环四次,然后判断坐标是否合法,如果合法就看看:
- 该位置的像素值是否与起始位置的原像素值相同
- 该位置的像素值是否与 color 不同
如果同时满足 "与起始位置的原像素值相同" 和 "与 color 不同",就将该位置的像素值修改成 color,然后基于这个位置继续深搜。
细节问题
回溯
本题不需要回溯操作,因为本题是直接将数组的值修改,因此不会重复走方格,也就不需要进行回溯操作了。
剪枝
本题是将所有满足条件的方格都遍历到,因此也不涉及到剪枝操作。
递归出口
矩阵中没有满足条件的方格可以递归的时候自然就结束递归了,因此不需要额外设置递归出口。
代码实现
java
class Solution {
int[][] image;
int originColor, color, m, n;
int[] dx = {0, 0, -1, 1};
int[] dy = {-1, 1, 0, 0};
public int[][] floodFill(int[][] givenImage, int sr, int sc, int givenColor) {
image = givenImage; color = givenColor;
m = image.length; n = image[0].length;
// 从[sr,sc]位置开始递归,递归前先记录原像素值
originColor = image[sr][sc];
// 判断当前的像素值是否与color相同,不同就修改
if (originColor != color) {
image[sr][sc] = color;
}
dfs(sr, sc);
return image;
}
private void dfs(int row, int col) {
// 从[row,col]位置开始向四个方向搜索
for (int k = 0; k < 4; k++) {
int x = row + dx[k], y = col + dy[k];
// 判断下标是否合法
if (x >= 0 && x < m && y >= 0 && y < n) {
// 判断当前位置的像素值是否与起始位置的像素值相同,并且是否与color不同
if (image[x][y] == originColor && image[x][y] != color) {
// 修改像素值
image[x][y] = color;
dfs(x, y);
}
}
}
}
}
文章到这里就告一段落了,若有错误请尽管指出~
完