1. FloodFill算法:洪水灌溉的艺术
FloodFill算法,这个听起来充满诗意的名字,实际上是一种在二维网格中处理连通区域的高效算法。想象一下,当你用油漆桶工具点击图片的某个区域时,颜色就像洪水一样蔓延开来,直到遇到不同颜色的边界——这就是FloodFill最直观的体现。
1.1 算法核心思想
FloodFill的核心在于"标记即永恒"的原则。与回溯算法不同,FloodFill一旦访问并标记了某个位置,就再也不会回头。这种特性使得它的时间复杂度稳定在O(M×N),其中M和N分别是网格的行数和列数。
算法通常有两种实现方式:
- DFS(深度优先搜索):递归实现,代码简洁
- BFS(广度优先搜索):队列实现,避免栈溢出
1.2 与回溯算法的本质区别
回溯算法和FloodFill虽然都使用递归,但有着根本的不同:
| 特性 | 回溯算法 | FloodFill |
|---|---|---|
| 恢复现场 | 需要 | 不需要 |
| 访问次数 | 可能多次访问同一位置 | 每个位置只访问一次 |
| 适用场景 | 寻找所有可能解 | 统计连通区域或染色 |
| 时间复杂度 | 通常较高(指数级) | O(M×N) |
| 典型问题 | 八皇后、全排列 | 图像渲染、岛屿数量 |
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 图像渲染:FloodFill的Hello World
2.1 问题描述
图像渲染是FloodFill最经典的应用。给定一个表示图像的二维数组,从指定的(sr, sc)位置开始,将所有与初始位置颜色相同且相连的区域染成新的颜色。
关键点:
- 相连指的是上下左右四个方向
- 需要处理新旧颜色相同的情况(否则会死循环)
- 可以直接修改原数组作为访问标记
2.2 实现细节与技巧
cpp复制class Solution {
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
if(image[sr][sc] == newColor) return image; // 重要特判
int oldColor = image[sr][sc];
dfs(image, sr, sc, oldColor, newColor);
return image;
}
void dfs(vector<vector<int>>& image, int i, int j, int oldColor, int newColor) {
if(i < 0 || i >= image.size() || j < 0 || j >= image[0].size() || image[i][j] != oldColor) {
return;
}
image[i][j] = newColor;
dfs(image, i+1, j, oldColor, newColor);
dfs(image, i-1, j, oldColor, newColor);
dfs(image, i, j+1, oldColor, newColor);
dfs(image, i, j-1, oldColor, newColor);
}
};
注意事项:
- 边界检查必须放在递归最开始,避免数组越界
- 颜色判断要在边界检查之后,否则可能访问非法内存
- 四个方向的递归可以用方向数组简写
3. 岛屿问题系列
3.1 岛屿数量问题
统计二维网格中岛屿的数量,其中'1'表示陆地,'0'表示水。
解题思路:
- 遍历整个网格
- 遇到'1'时,岛屿计数加1,并用FloodFill将该岛屿所有'1'标记为已访问
- 标记可以通过修改原数组(沉岛)或使用额外vis数组
code复制
