BFS 解决 FloodFill 算法
- 1.图像渲染
- 2.岛屿数量
- 3.岛屿的最大面积
- 4.被围绕的区域
点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃
FloodFill 算法 就是在一个矩阵中找性质相同的连通块。关于这个在《递归、搜索回溯专题》 有详细介绍。并且用的是DFS解决问题,这里主要是用BFS解决FloodFill 算法。
1.图像渲染
题目链接:733. 图像渲染
题目分析:
这道题的意思是,给一个开始位置,把和它性质相同的连通块都找到,并且渲染成color。注意可以上下左右四个方向去找。
算法原理:
解法:BFS
BFS(宽度优先遍历/宽度优先搜索/层序遍历),借助队列实现,一层一层出。
起始位置先入队。队列不空出队,把它上下左右和它颜色相同的放入队列。然后循环下去,直到队列为空。
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 -> bauto [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,也不会进去了。
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类型的二维数组来标记那些土地是已经被搜索过了!搜索过了下一次就不能找了。
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’ 区域
- 扫描矩阵,还原即可
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] = '.';}}}}
};