flood fill算法笔记 :
在图种判断连通块的一种经典算法, flood fill, 请读者解决下列问题。
417. 太平洋大西洋水流问题 - 力扣(LeetCode)
预备:
flood fill的根本实现其实只是BFS和DFS的变体。 我们拿130举例。
这个算法的思路就和他的名字一样,从一个地方向另一个地方流动,我们解决这样的问题,无非就是枚举每个点,然后向四周进行递归,思路是非常简单的,而且代码套路实在是千篇一律。
我们来看题目。
并且我个人习惯使用DFS,因为BFS需要队列,DFS相对简洁一些。
200. 岛屿数量 - 力扣(LeetCode)
class Solution {
public:
vector<vector<char>> g;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int numIslands(vector<vector<char>>& grid) {
g = grid;
int cnt = 0;
for (int i = 0; i < grid.size(); i ++) {
for (int j = 0; j < grid[i].size(); j++) {
if (g[i][j] == '1') {
dfs(i, j);
cnt++;
}
}
}
return cnt;
}
void dfs(int x, int y )
{
g[x][y] = 0;
for (int i = 0; i < 4; i ++) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < g.size() && b >= 0 && b < g[a].size() && g[a][b] == '1') {
dfs(a, b);
}
}
}
};
代码量非常短, 这道题是入门题目,我们枚举每个点,然后假如周围有1,我们继续向这个方向搜索。注意要搜索到所有的连通块才算一个岛屿。
130. 被围绕的区域 - 力扣(LeetCode)
这道题我们需要反向考虑,我们从四周向中心去枚举,这样我们首先把边界上的o排除,剩下的就是需要改成X的答案。
class Solution {
public:
int n, m;
vector<vector<char>> board;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void solve(vector<vector<char>>& _board) {
board = _board;
n = board.size();
if (!n) return;
m = board[0].size();
for (int i = 0; i < n; i ++ ) {
if (board[i][0] == 'O') dfs(i, 0);
if (board[i][m - 1] == 'O') dfs(i, m - 1);
}
for (int i = 0; i < m; i ++ ) {
if (board[0][i] == 'O') dfs(0, i);
if (board[n - 1][i] == 'O') dfs(n - 1, i);
}
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (board[i][j] == '#') board[i][j] = 'O';
else board[i][j] = 'X';
_board = board;
}
void dfs(int x, int y) {
board[x][y] = '#';
for (int i = 0; i < 4; i ++ ) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && board[a][b] == 'O')
dfs(a, b);
}
}
};
417. 太平洋大西洋水流问题 - 力扣(LeetCode)
还是一样的问题,从边界向中心枚举,唯一要注意的是判断条件,只有向中心方向的高度大于当前点高度,我们才可以流动。我这里用了两个bool数组为了更清晰的讲解,其实可以用一个int表示,那种写法空间更优,但是不好理解,这里就不写了。
class Solution {
public:
int n, m;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(vector<vector<int>>& heights, vector<vector<bool>>& used, int x, int y)
{
if (used[x][y]) return;
used[x][y] = true;
for (int i = 0; i < 4; i ++)
{
int a = x + dx[i] , b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && heights[a][b] >= heights[x][y] ) {
dfs(heights, used, a, b);;
}
}
return;
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
n = heights.size(), m = heights[0].size();
vector<vector<bool>> pac(n, vector<bool>(m, false));
vector<vector<bool>> atl(n, vector<bool>(m, false));
for (int i = 0; i < n; i++ )
{
dfs(heights, pac, i, 0);
dfs(heights, atl, i, m - 1);
}
for (int i = 0; i < m; i ++)
{
dfs(heights, pac, 0, i);
dfs(heights, atl, n - 1, i);
}
vector<vector<int>> res;
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < m; j ++)
{
if (pac[i][j] && atl[i][j]) res.push_back({i, j});
}
}
return res;
}
};
1020. 飞地的数量 - 力扣(LeetCode)
一样的边界向中心点,就当练习代码熟练度了。
class Solution {
public:
vector<vector<int>> g;
int n , m;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(int x, int y)
{
g[x][y] = 0;
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && g[a][b]) {
dfs(a, b);
}
}
}
int numEnclaves(vector<vector<int>>& grid) {
g = grid;
n = grid.size();
m = grid[0].size();
for (int i = 0; i < n; i++) {}
for (int j = 0; j < m; j ++) {
if (!i || !j || i == n - 1 || j == m - 1) {
if (g[i][j]) {
dfs(i, j);
}
}
}
}
int res = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j ++) {
res += g[i][j];
}
}
return res;
}
};
}
}
int res = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j ++) {
res += g[i][j];
}
}
return res;
}
};
以上几题难度简单,适合熟悉DFS, 谢谢观看。