BFS 解决 FloodFill 算法
点赞 👍👍收藏 🌟🌟关注 💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃
FloodFill 算法 就是在一个矩阵中找性质相同的连通块。关于这个在《递归、搜索回溯专题》 有详细介绍。并且用的是DFS解决问题,这里主要是用BFS解决FloodFill 算法。
1.图像渲染
题目链接: 733. 图像渲染
题目分析:
这道题的意思是,给一个开始位置,把和它性质相同的连通块都找到,并且渲染成color。注意可以上下左右四个方向去找。
算法原理:
解法:BFS
BFS(宽度优先遍历/宽度优先搜索/层序遍历),借助队列实现,一层一层出。
起始位置先入队。队列不空出队,把它上下左右和它颜色相同的放入队列。然后循环下去,直到队列为空。
cpp
class Solution
{
//处理数对,经常用到pair,可以typedef一下
typedef pair<int,int> PII;
//向量数组
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color)
{
if(image[sr][sc] == color) return image;//处理边界情况
int prev = image[sr][sc];//先标记一下需要修改的像素值
int m = image.size(), n = image[0].size();
queue<PII> q;
q.push({sr,sc});
while(q.size())
{
//first -> a, second -> b
auto [a,b] = q.front();
q.pop();
image[a][b] = color;
//上下左右四个方向
for(int i = 0; i < 4; ++i)
{
int x = a + dx[i], y = b + dy[i];
if(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == prev)
{
q.push({x,y});
}
}
}
return image;
}
};
2.岛屿数量
题目链接: 200. 岛屿数量
题目描述:
求岛屿的数量,每座岛屿只能上下左右去找。
算法原理:
解法:BFS
从左往右扫描这个矩阵,当遇到陆地的时候就把和陆地相连的岛屿找到,如何找,就是BFS从这个地方宽搜一遍,就可以把连通的区域找到。可以搞一个变量ret 记录陆地数量就可以。但是这里层序遍历有一个问题。从一个位置扩展到下一个位置,不能在从下一个位置在回到上一个位置不然就死循环了。为了避免这种情况我们有两种方式。
- 修改原始矩阵的值
- 搞一个同等矩阵大小的bool类型的二维数组,记录当前位置是否已经被搜索过,false表示没有,true表示搜索过。并且当前位置bfs一次之后。和它相连的其他岛屿也被置为true,然后从左往右遍历的时候即使它是1,也不会进去了。
cpp
class Solution
{
//bool vis[301][301]; //感觉浪费空间就先计算一下当前需要多大空间,然后再申请
vector<vector<int>> vis;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m,n;
public:
int numIslands(vector<vector<char>>& grid)
{
m = grid.size(), n = grid[0].size();
vis.resize(m,vector<int>(n));
int ret = 0;
for(int i = 0; i < m; ++i)
{
for(int j = 0; j < n; ++j)
{
if(grid[i][j] == '1' && !vis[i][j])
{
ret++;
bfs(grid,i,j);
}
}
}
return ret;
}
void bfs(vector<vector<char>>& grid, int i, int j)
{
queue<pair<int,int>> q;
q.push({i,j});
vis[i][j] = true;
while(q.size())
{
auto [a,b] = q.front();
q.pop();
for(int k = 0; k < 4; ++k)
{
int x = a + dx[k], y = b + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] == '1')
{
q.push({x,y});
vis[x][y] = true;
}
}
}
}
};
3.岛屿的最大面积
题目链接: 695. 岛屿的最大面积
题目分析:
这道题是求那一个连通块的面积是最大的。
算法原理:
解法:BFS
还是从左往右扫完,当碰到一块土地就去找和这个土地连通的所有土地,如何找?还是用BFS遍历一次,同时要有一个变量count统计这个岛屿面积有多大。注意找过的土地下一次不能在找了!因此我们还是来一个bool类型的二维数组来标记那些土地是已经被搜索过了!搜索过了下一次就不能找了。
cpp
class Solution
{
bool vis[51][51];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m, n;
public:
int maxAreaOfIsland(vector<vector<int>>& grid)
{
int ret = 0;
m = grid.size(), n = grid[0].size();
for(int i = 0; i < m; ++i)
{
for(int j = 0; j < n; ++j)
{
if(grid[i][j] == 1 && !vis[i][j])
{
ret = max(ret,bfs(grid, i, j));
}
}
}
return ret;
}
int bfs(vector<vector<int>>& gird, int i, int j)
{
int count = 0;
queue<pair<int,int>> q;
q.push({i,j});
vis[i][j] = true;
++count;
while(q.size())
{
auto [a,b] = q.front();
q.pop();
for(int k = 0; k < 4; ++k)
{
int x = a + dx[k], y = b + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && gird[x][y] == 1 && !vis[x][y])
{
q.push({x,y});
vis[x][y] = true;
++count;
}
}
}
return count;
}
};
4.被围绕的区域
题目链接: 130. 被围绕的区域
题目分析:
把被 ' X ' 围绕的 ' O '区域修改为 ' X ',被围绕的区域指的是这个区域的 ' O ' 没有处于边界。
算法原理:
如下面这张图只有一处区域是要被修改的,此时我们是有两种解法的。
解法一:直接做
从左往右扫描,当遇到 'O' 之后,就把与这个 'O' 相连的 'O' 区域都修改成 'X',这是我们之前做的方式。但是这里有一个问题当我在扫描遇到 'O' 也会把下面绿色区域修改成 'X' ,但是这块区域有 'O' 是处于边界的,因此这一块区域是不能够被修改的!所以在BFS过程中遇到 'O' 处于边界的情况这块是不能被修改的。
更为极端的例子是,当BFS是把这个区域遍历一遍之后才知道这个区域是不能够被修改的,还要把已经被修改过成 'X' 还原成 'O'。但是我们BFS是一边修改一边遍历的。然后遍历到 'O' 处于边界才知道这个区域是不能被修改的,并且刚才修改过的是错的,还要还原回去,但此时前面变成 'X' 的 'O' 特别难被还原回去。
不过还可以这样,先去BFS遍历一遍看看这个区域是否合法,如果合法在去BFS把这块区域修改成 'X',需要两个BFS。
解法二:正难则反
正着来不太好处理与边界相连的连通块,那就反着来就先处理与边相连的连通块。先遍历四条边界,在四条边界发现有 'O' ,仅对这些边界上的 'O' 来一次BFS,把这个连通块都修改成 '.'。这样把处于边界的 'O' 连通快都修改成 '.'之后,接下来仅需遍历一下矩阵,把矩阵中的剩下的 'O' 修改成 'X' ,把 '.' 还原成 'O'就可以了。
- 先处理边界上 'O' 区域
- 扫描矩阵,还原即可
cpp
class Solution {
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int m,n;
public:
void solve(vector<vector<char>>& board) {
m=board.size(),n=board[0].size();
// 1.把边界的 O 相连的连通块,全部修改成 .
for(int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if(board[i][j] == 'O')
if(i == 0 || i == m-1 || j == 0 || j == n-1)
bfs(board,i,j);
// 2.还原
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
{
if(board[i][j] == 'O') board[i][j]='X';
else if(board[i][j] == '.') board[i][j]='O';
}
}
void bfs(vector<vector<char>>& board, int i, int j)
{
queue<pair<int,int>> q;
q.push({i,j});
board[i][j] = '.';
while(q.size())
{
auto [a,b] = q.front();
q.pop();
for(int k = 0; k < 4; ++k)
{
int x = a + dx[k], y = b + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O')
{
q.push({x,y});
board[x][y] = '.';
}
}
}
}
};