自己搭服务器 做购物网站成本,网站设计与网页制作项目教程,wordpress分享插件下载,哪个网站可以做奖状目录
FloodFill 算法
题目一#xff1a;图像渲染
题目二#xff1a;岛屿数量
题目三#xff1a;岛屿的最大面积
题目四#xff1a;被围绕的区域 FloodFill 算法
在递归搜索回溯中已经说到过 FloodFill 算法了#xff0c;但是那里是用 dfs 解决的#xff0c;这里会使…目录
FloodFill 算法
题目一图像渲染
题目二岛屿数量
题目三岛屿的最大面积
题目四被围绕的区域 FloodFill 算法
在递归搜索回溯中已经说到过 FloodFill 算法了但是那里是用 dfs 解决的这里会使用 bfs 解决
FloodFill 算法(中文洪水灌溉)
也就是找出性质相同的联通块
例如下图找出有几块会被洪水灌溉的区域其中负数表示凹下去的地面正数表示凸起的地面 此时就会有两片区域会被洪水灌溉也有问灌溉区域最大的面积是多少或是灌溉区域最大的边是多少等等
按左边那个大的区域举例之前的dfs就是先一条路走到不能走时再退回去找其他路也就是下面的紫色箭头的方式 而bfs则是一层一层的扩展每一层都关注该层的上下左右是否能扩展到其他地方即下图所示 共扩展了三层就能够走完这个区域这就是bfs的方式
总而言之都是找出性质相同的联通块 题目一图像渲染
有一幅以 m x n 的二维整数数组表示的图画 image 其中 image[i][j] 表示该图画的像素值大小。
你也被给予三个整数 sr , sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。
为了完成 上色工作 从初始像素开始记录初始坐标的 上下左右四个方向上 像素值与初始坐标相同的相连像素点接着再记录这四个方向上符合条件的像素点与他们对应 四个方向上 像素值与初始坐标相同的相连像素点……重复该过程。将所有有记录的像素点的颜色值改为 newColor 。
最后返回 经过上色渲染后的图像 。
示例 1: 输入: image [[1,1,1],[1,1,0],[1,0,1]]sr 1, sc 1, newColor 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析: 在图像的正中间(坐标(sr,sc)(1,1)),在路径上所有符合条件的像素点的颜色都被更改成2。
注意右下角的像素没有更改为2因为它不是在上下左右四个方向上与初始点相连的像素点。示例 2:
输入: image [[0,0,0],[0,0,0]], sr 0, sc 0, newColor 2
输出: [[2,2,2],[2,2,2]] 这道题的题意就是给我们一个起始位置(sr, sc)找到与起始位置相连且像素值相同的区域都修改为newColor
也就是使用层序遍历先找出起始位置的上下左右是否有相连的相同数字块找到后接下来再找刚刚找到的这些数字块的上下左右有没有相连的直到没有为止
并且在扩展的过程中将像素值再修改为 newColor
在书写bfs时非常常用的技巧就是设置两个数组dx和dy他们对应的位置组合来表示上下左右的移动即dx[4] {0, 0, 1, -1}dy[4] {1, -1, 0, 0}
对应位置组合为(0, 1)(0, -1)(1, 0)(-1, 0)
让原本的坐标加上对应的这四个坐标就能够完美表示上下左右的移动
代码如下
class Solution
{// 简便表示pairtypedef重命名一下typedef pairint, int PII;int dx[4] {0, 0, 1, -1};int dy[4] {1, -1, 0, 0};
public:vectorvectorint floodFill(vectorvectorint image, int sr, int sc, int color) {// 记录原本的像素值int prev image[sr][sc];int m image.size(), n image[0].size();// 边界条件if(prev color) return image;queuePII q;q.push({sr, sc});// 层序遍历while(!q.empty()){// 这样可以简便的取出pair里的内容不需要使用firstsecondauto [a, b] q.front();q.pop();image[a][b] color;for(int i 0; i 4; i){// x、y是上下左右移动后的新坐标int x a dx[i];int y b dy[i];// 需要判断x、y是否越界访问imageif(x 0 x m y 0 y n image[x][y] prev)q.push({x, y});}}return image;}
}; 题目二岛屿数量
给你一个由 1陆地和 0水组成的的二维网格请你计算网格中岛屿的数量。
岛屿总是被水包围并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外你可以假设该网格的四条边均被水包围。
示例 1
输入grid [[1,1,1,1,0],[1,1,0,1,0],[1,1,0,0,0],[0,0,0,0,0]
]
输出1示例 2
输入grid [[1,1,0,0,0],[1,1,0,0,0],[0,0,1,0,0],[0,0,0,1,1]
]
输出3 依旧是使用bfs的方式这道题需要注意的是
全是1的联通块是一个岛屿但是在遍历时有可能会重复计算同一块假设第一块的右边第二块也是1此时遍历到第一块时会计算第二块而遍历到第二块时也可能会找到第一块这样会导致死循环一直遍历
解决方式就是创建一个与原数组一样大的数组vis都是bool类型的每遍历到一块区域就将vis数组中对应位置的数设置为true这样就不会重复遍历了
所以下面代码实现时每次遍历到一个位置时需要将vis数组中的该位置改为true之后只有当vis数组对应位置为false时才遍历
代码如下
class Solution
{typedef pairint, int PII;// 判断数组用于判断该位置是否被遍历过bool vis[301][301];int dx[4] {0, 0, -1, 1};int dy[4] {-1, 1, 0, 0};// m、n定义为全局的便于bfs函数能取到值int m, n;
public:int numIslands(vectorvectorchar 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){// 当等于1时还需要判断vis数组中对应位置是否为falseif(grid[i][j] 1 vis[i][j] false){// 每进入一次层序遍历表示找到了一个岛retret;bfs(grid, i, j);}}}return ret;}// bfs层序遍历函数void bfs(vectorvectorchar grid, int i, int j){queuePII q;q.push({i, j});vis[i][j] true;while(!q.empty()){auto [a, b] q.front();q.pop();for(int num 0; num 4; num){// 上下左右四块int x a dx[num];int y b dy[num];// 判断不越界的同时还需要判断vis数组是否为falseif(x 0 x m y 0 y n grid[x][y] 1 vis[x][y] false){// 每次遍历到后将vis数组对应位置改为truevis[x][y] true;q.push({x, y});}}}}
}; 题目三岛屿的最大面积
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0代表水包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿则返回面积为 0 。
示例 1 输入grid [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出6
解释答案不应该是 11 因为岛屿只能包含水平或垂直这四个方向上的 1
示例 2
输入grid [[0,0,0,0,0,0,0,0]]
输出0 这道题与上一题一样也是需要vis数组标记某个位置是否遍历过方法也与上一题几乎一模一样只是在统计每一岛屿时加了一个变量count每次入队列时count最后返回给主函数即可
代码如下
class Solution
{
public:typedef pairint, int PII;// 判断数组用于判断该位置是否被遍历过bool vis[60][60];int dx[4] {0, 0, -1, 1};int dy[4] {-1, 1, 0, 0};// m、n定义为全局的便于bfs函数能取到值int m, n;int maxAreaOfIsland(vectorvectorint grid) {m grid.size(), n grid[0].size();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] false){int num bfs(grid, i, j);ret max(ret, num);}}}return ret;}int bfs(vectorvectorint grid, int i, int j){int count 0;queuePII q;q.push({i, j});count;vis[i][j] true;while(!q.empty()){auto [a, b] q.front();q.pop();for(int k 0; k 4; k){int x a dx[k];int y b dy[k];if(x 0 x m y 0 y n grid[x][y] 1 vis[x][y] false){q.push({x, y});count;vis[x][y] true;}}}return count;}
}; 题目四被围绕的区域
给你一个 m x n 的矩阵 board 由若干字符 X 和 O 组成捕获 所有 被围绕的区域
连接一个单元格与水平或垂直方向上相邻的单元格连接。区域连接所有 O 的单元格来形成一个区域。围绕如果您可以用 X 单元格 连接这个区域并且区域中没有任何单元格位于 board 边缘则该区域被 X 单元格围绕。
通过将输入矩阵 board 中的所有 O 替换为 X 来 捕获被围绕的区域。
示例 1
输入board [[X,X,X,X],[X,O,O,X],[X,X,O,X],[X,O,X,X]]
输出[[X,X,X,X],[X,X,X,X],[X,X,X,X],[X,O,X,X]]
解释 在上图中底部的区域没有被捕获因为它在 board 的边缘并且不能被围绕。
示例 2
输入board [[X]]
输出[[X]] 题目要求就是联通块中不能存在边缘的方块否则就不改变边缘指 m * n 的四周那一圈
解法一直接做
这道题最容易想到的思路就是直接做
遇到联通块时先遍历一下这个联通快判断这个区域内是否有边缘块如果没有就改变如果有就不改变这种做法是需要每次遍历两遍联通块比较复杂下面看解法二
解法二正难则反
既然正着做这道题比较困难那就反着做题目要求不能联通块不能出现在边缘所以我们可以先从边缘开始判断对边缘区域的联通块先层序遍历将这些边缘区域的○修改为
此时矩阵中剩余的○就是符合题意的这时遍历整个矩阵如果有○全部修改为×
最后再将刚刚边缘改为的位置再改回○即可
代码如下
class Solution {
public:typedef pairint, int PII;// 判断数组用于判断该位置是否被遍历过int dx[4] {0, 0, -1, 1};int dy[4] {-1, 1, 0, 0};// m、n定义为全局的便于bfs函数能取到值int m, n;void solve(vectorvectorchar board) {m board.size(), n board[0].size();// 将边缘区域为O的先全部变为for(int i 0; i m; i){if(board[i][0] O) bfs(board, i, 0);if(board[i][n - 1] O) bfs(board, i, n - 1);}for(int j 0; j n; j){if(board[0][j] O) bfs(board, 0, j);if(board[m - 1][j] O) bfs(board, m - 1, j);}// 再将剩余的O变为X变为Ofor(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;}// bfs实现边缘区域的O变void bfs(vectorvectorchar board, int i, int j){queuePII q;q.push({i, j});board[i][j] ;while(!q.empty()){auto [a, b] q.front();q.pop();for(int k 0; k 4; k){int x a dx[k];int y b dy[k];if(x 0 x m y 0 y n board[x][y] O){q.push({x, y});board[x][y] ;}}}}
}; BFS解决 FloodFill 算法的题目到此结束