目录
[1. 题目链接:733. 图像渲染](#1. 题目链接:733. 图像渲染)
[2. 题目描述:](#2. 题目描述:)
[3. 解法](#3. 解法)
[1. 题目链接:200. 岛屿数量](#1. 题目链接:200. 岛屿数量)
[2. 题目描述:](#2. 题目描述:)
[3. 解法](#3. 解法)
[1. 题目链接:695. 岛屿的最大面积](#1. 题目链接:695. 岛屿的最大面积)
[2. 题目描述:](#2. 题目描述:)
[3. 解法(深搜dfs)](#3. 解法(深搜dfs))
[1. 题目链接:130. 被围绕的区域](#1. 题目链接:130. 被围绕的区域)
[2. 题目描述:](#2. 题目描述:)
[3. 解法](#3. 解法)
一、图像渲染
1. 题目链接:733. 图像渲染
2. 题目描述:
有一幅以
m x n
的二维整数数组表示的图画image
,其中image[i][j]
表示该图画的像素值大小。你也被给予三个整数
sr
,sc
和color
。你应该从像素image[sr][sc]
开始对图像进行 上色填充 。为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 相邻且同色的像素点,接着再记录与这些像素点相邻且同色的新像素点,......,重复该过程。将所有有记录的像素点的颜色值改为
color
。最后返回 经过上色渲染后的图像。
示例 1:
输入: image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, color = 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, color = 0 输出: [[0,0,0],[0,0,0]]
提示:
m == image.length
n == image[i].length
1 <= m, n <= 50
0 <= image[i][j], color < 216
0 <= sr < m
0 <= sc < n
3. 解法
🌴算法思路:
可以利用「深搜」或者「宽搜」,遍历到与该点相连的所有「像素相同的点」,然后将其修改成指定的像素即可。
递归函数设计:
参数:
a. 原始矩阵;
b. 当前所在的位置;
c. 需要修改成的颜色。
函数体:
a. 先将该位置的颜色改成指定颜色(因为我们的判断,保证每次进入递归的位置都是需要修改的位置);
b. 遍历四个方向上的位置:
- 如果当前位置合法,并且与初始颜色相同,就递归进去。
🌴算法代码:
cpp
class Solution
{
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m, n;
int prev;
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color)
{
if (image[sr][sc] == color) return image;
m = image.size(), n = image[0].size();
prev = image[sr][sc];
dfs(image, sr, sc, color);
return image;
}
void dfs(vector<vector<int>>& image, int i, int j, int color)
{
image[i][j] = color;
for (int k = 0; k < 4; k++)
{
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < m && y >=0 && y < n && image[x][y] == prev)
{
dfs(image, x, y, color);
}
}
}
};
二、岛屿数量
1. 题目链接:200. 岛屿数量
2. 题目描述:
给你一个由
'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'
3. 解法
🌴算法思路:
遍历整个矩阵,每次找到「⼀块陆地」的时候:
- 说明找到「⼀个岛屿」,记录到最终结果 ret 里面;
- 并且将这个陆地相连的所有陆地,也就是这块「岛屿」,全部「变成海洋」。这样的话,我们下次遍历到这块岛屿的时候,它「已经是海洋」了,不会影响最终结果。
- 其中「变成海洋」的操作,可以利用「深搜」和「宽搜」解决,其实就是 [733. 图像渲染]( "733. 图像渲染") 这道题~
这样,当我们,遍历完全部的矩阵的时候, ret 存的就是最终结果。
🌴算法流程:
- 初始化 ret = 0 ,记录目前找到的岛屿数量;
- 双重循环遍历二维网格,每当遇到一块陆地,标记这是一个新的岛屿,然后将这块陆地相连的陆地全部变成海洋。
递归函数的设计:
-
把当前格子标记为水;
-
向上、下、左、右四格递归寻找陆地,只有在下标位置合理的情况下,才会进入递归:
- 下一个位置的坐标合理;
- 并且下一个位置是陆地。
🌴算法代码:
cpp
class Solution
{
vector<vector<bool>> vis;
int m, n;
public:
int numIslands(vector<vector<char>>& grid)
{
m = grid.size(), n = grid[0].size();
vis = vector<vector<bool>>(m, vector<bool>(n));
int ret = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if (!vis[i][j] && grid[i][j] == '1')
{
ret++;
dfs(grid, i, j);
}
}
return ret;
}
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
void dfs(vector<vector<char>>& grid, int i, int j)
{
vis[i][j] = true;
for (int k = 0; k < 4; k++)
{
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && !vis[x][y])
{
dfs(grid, x, y);
}
}
}
};
三、岛屿的最大面积
1. 题目链接:695. 岛屿的最大面积
2. 题目描述:
给你一个大小为
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
3. 解法(深搜dfs)
🌴算法思路:
-
遍历整个矩阵,每当遇到⼀块土地的时候,就用「深搜」或者「宽搜」将与这块土地相连的「整个岛屿」的面积计算出来。
-
然后在搜索得到的「所有的岛屿面积」求⼀个「最大值」即可。
-
在搜索过程中,为了「防止搜到重复的土地」:
- 可以开一个同等规模的「布尔数组」,标记一下这个位置是否已经被访问过;
- 也可以将原始矩阵的 1 修改成 0 ,但是这样操作会修改原始矩阵。
🌴算法流程:
主函数内:
a. 遍历整个数组,发现⼀块没有遍历到的土地之后,就用 dfs ,将与这块土地相连的岛屿的面积求出来;
b. 然后将面积更新到最终结果 ret 中。
深搜函数 dfs 中:
a. 能够进到 dfs 函数中,说明是一个没遍历到的位置;
b. 标记一下已经遍历过,设置一个变量 S = 1 (当前这个位置的面积为 1 ),记录最终的面积;
c. 上下左右遍历四个位置:
- 如果找到⼀块没有遍历到的土地,就将与这块土地相连的岛屿面积累加到 S 上;
d. 循环结束后, S 中存的就是整块岛屿的面积,返回即可。
🌴算法代码:
cpp
class Solution
{
vector<vector<bool>> vis;
int m, n;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int count;
public:
int maxAreaOfIsland(vector<vector<int>>& grid)
{
m = grid.size(), n = grid[0].size();
vis = vector<vector<bool>>(m, vector<bool>(n));
int ret = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if (!vis[i][j] && grid[i][j] == 1)
{
count = 0;
dfs (grid, i, j);
ret = max(ret, count);
}
}
return ret;
}
void dfs (vector<vector<int>>& grid, int i, int j)
{
count++;
vis[i][j] = true;
for (int k = 0; k < 4; k++)
{
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] == 1)
{
dfs (grid, x, y);
}
}
}
};
四、被围绕的区域
1. 题目链接:130. 被围绕的区域
2. 题目描述:
给你一个
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 == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j]
为'X'
或'O'
3. 解法
🌴算法思路:
正难则反
可以先利用 dfs 将与边缘相连的 '0' 区域做上标记,然后重新遍历矩阵,将没有标记过的 '0' 修改成 'X' 即可。
🌴算法代码:
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 j = 0; j < n; j++)
{
if (board[0][j] == 'O') dfs(board, 0, j);
if (board[m - 1][j] == 'O') dfs(board, m - 1, j);
}
for (int i = 0; i < m; i++)
{
if (board[i][0] == 'O') dfs(board, i, 0);
if (board[i][n - 1] == 'O') dfs(board, i, n - 1);
}
// 2.还原
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if (board[i][j] == '.') board[i][j] = 'O';
else if (board[i][j] == 'O') board[i][j] = 'X';
}
}
void dfs(vector<vector<char>>& board, int i, int j)
{
board[i][j] = '.';
for (int k = 0; k < 4; k++)
{
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O')
{
dfs(board, x, y);
}
}
}
};