赞
踩
目录
FloodeFill算法即填充算法,中文:洪水灌溉,算法原理就是从一个点开始向四周扩散,向周围可以走到的点填充颜色,直到将可扩散到的点全部填充颜色。
通常使用下面两种方法解决FloodFill算法问题:
假设这一块4*4的方格是一块土地,有凸起的地方,也有凹陷的地方(凹陷的地方用负数表示)。此时下大雨发洪水,会把凹陷的地方填满。绿色圈起来的属于一块区域(上下左右四个方向,有时候题目也会问八个方向包括斜着相连的),题目会问有多少块区域被填满,或者问被填满的最大区域是哪个,或某一块区域的边长是多少。但是本质都是在一块区域找性质相同的连通块。
DFS:深度优先遍历(递归):从某一点开始一条路走到黑。以最右列的为例,从-1出发,向下->-2->-10->-12,此时发现-12的上下左右都走不了,在拐回去到-10,然后发现-10左边可以走->-4->-3。
BFS:宽度优先遍历:一层一层拨开。还是以最右边为例,从-1开始拓展一层(上下左右)发现能把-2扩展出来,接着继续扩展一层上下左右,-3和-10扩展出来;接着在扩展一层上下左右,把-4和-12扩展出来。
这时常用两个数组来遍历结点的上下左右结点:
- int dx[4] = {0, 0 , -1, 1}; // i点加dx,dy就是i点的上下左右下标
-
- int dy[4] = {1, -1 , 0, 0};
难度 简单
有一幅以 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]]
提示:
m == image.length
n == image[i].length
1 <= m, n <= 50
0 <= image[i][j], newColor < 216
0 <= sr < m
0 <= sc < n
- class Solution {
- public:
- vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
-
- }
- };
可以利用深搜或者宽搜,遍历到与该点相连的所有像素相同的点,然后将其修改成指定的像素即可。后面深搜专题用深搜写,这里用宽搜写:
- class Solution {
- int dx[4] = {0, 0 , -1, 1}; // i点加dx,dy就是i点的上下左右下标
- int dy[4] = {1, -1 , 0, 0};
-
- public:
- vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
- int prev = image[sr][sc];
- if(prev == color)
- return image;
-
- int m = image.size(), n = image[0].size(); // 获取大小防止越界
- queue<pair<int, int>> q; // 存下标
- q.push({sr, sc});
- while(!q.empty()) // 模拟层序遍历
- {
- auto [a, b] = q.front(); // 拿到队头的元素(一个pair)
- 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;
- }
- };

难度 中等
给你一个由 '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
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j]
的值为 '0'
或 '1'
- class Solution {
- public:
- int numIslands(vector<vector<char>>& grid) {
-
- }
- };
遍历整个矩阵,每次找到一块陆地的时候:说明找到一个岛屿,记录到最终结果 ret 里面。
并且将这个陆地相连的所有陆地,也就是这块岛屿,全部变成海洋。这样的话,下次遍历到这块岛屿的时候,它已经是海洋了,不会影响最终结果。
其中变成海洋的操作,可以利用深搜或宽搜解决,其实就是力扣733. 图像渲染这道题。这样,遍历完全部的矩阵的时候, ret 存的就是最终结果。
(这里用全局bool数组来判断陆地是否被遍历过,也可以直接修改数组,面试的时候可以问面试官是否可以直接修改数组)
- class Solution {
- int dx[4] = {0, 0 , -1, 1}; // i点加dx,dy就是i点的上下左右下标
- int dy[4] = {1, -1 , 0, 0};
- bool vis[301][301] = {false}; // 开题目范围大小
- int m = 0, n = 0;
-
- public:
- int numIslands(vector<vector<char>>& 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;
- 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.empty())
- {
- auto [a, b] = q.front();
- q.pop();
- 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 && grid[x][y] == '1' && !vis[x][y])
- {
- q.push({ x, y });
- vis[x][y] = true;
- }
- }
- }
- }
- };

难度 中等
给你一个大小为 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
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j]
为 0
或 1
- class Solution {
- public:
- int maxAreaOfIsland(vector<vector<int>>& grid) {
-
- }
- };
遍历整个矩阵,每当遇到一块土地的时候,就用深搜或者宽搜将与这块土地相连的整个岛屿的面积计算出来。然后在搜索得到的所有的岛屿面积求一个最大值即可。
在搜索过程中,为了防止搜到重复的土地,可以开一个同等规模的bool数组,标记一下这个位置是否已经被访问过,也可以将原始矩阵的 1 修改成 0 ,但是这样操作会修改原始矩阵。
- class Solution {
- int dx[4] = {0, 0 , -1, 1}; // i点加dx,dy就是i点的上下左右下标
- int dy[4] = {1, -1 , 0, 0};
- bool vis[51][51] = {false};
- int m = 0, n = 0;
-
- public:
- int maxAreaOfIsland(vector<vector<int>>& 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])
- {
- ret = max(ret, bfs(grid, i, j));
- }
- }
- }
- return ret;
- }
-
- int bfs(vector<vector<int>>& grid, int i, int j)
- {
- int ret = 0;
- queue<pair<int, int>> q;
- q.push({ i, j });
- vis[i][j] = true; // 变成true就++ret
- ++ret;
- while (!q.empty())
- {
- auto [a, b] = q.front();
- q.pop();
- 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 && grid[x][y] == 1 && !vis[x][y])
- {
- q.push({ x, y });
- vis[x][y] = true;
- ++ret;
- }
- }
- }
- return ret;
- }
- };

难度 中等
给你一个 m x n
的矩阵 board
,由若干字符 'X'
和 'O'
,找到所有被 'X'
围绕的区域,并将这些区域里所有的 '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"]] 解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
示例 2:
输入:board = [["X"]] 输出:[["X"]]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j]
为 'X'
或 'O'
- class Solution {
- public:
- void solve(vector<vector<char>>& board) {
-
- }
- };
正难则反。 可以先利用 bfs 将与边缘相连的 'O' 区域修改成无关字符,然后重新遍历矩阵,将没有标记过的 'O' 全修改成 'X' 即可,再把无关字符全还原成'O'。
- class Solution {
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m = 0, n = 0;
-
- public:
- void solve(vector<vector<char>>& board) {
- m = board.size(), n = board[0].size();
- for(int i = 0; i < n; ++i) // 修改边界的O成无关字符
- {
- if(board[0][i] == 'O')
- bfs(board, 0, i);
- if(board[m - 1][i] == 'O')
- bfs(board, m - 1, i);
- }
- 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 i = 0; i < m; ++i) // 把剩下的O全修改成X,R全修改成O
- {
- for(int j = 0; j < n; ++j)
- {
- if(board[i][j] == 'O')
- board[i][j] = 'X';
- else if(board[i][j] == 'R')
- 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] = 'R';
- while(!q.empty())
- {
- auto [a, b] = q.front();
- q.pop();
- 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 && board[x][y] == 'O')
- {
- q.push({x, y});
- board[x][y] = 'R';
- }
- }
- }
- }
- };

下一篇动态规划类型的是01背包问题的OJ。
下下篇是BFS解决最短路类型的OJ。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。