主页 > 互联网  > 

FloodFill算法(典型算法思想)——OJ例题算法解析思路

FloodFill算法(典型算法思想)——OJ例题算法解析思路

目录

一、733. 图像渲染 - 力扣(LeetCode)

算法代码:

​代码思路

​问题描述

​算法选择

​代码结构

​代码详解

​1. 成员变量

​2. floodFill 函数

​参数:

​逻辑:

​3. dfs 函数

​参数:

​逻辑:

​代码优化

​边界检查优化

​使用 BFS

​空间优化

​示例运行

​总结

二、200. 岛屿数量 - 力扣(LeetCode)

算法代码: 

1. 问题描述

2. 代码思路

初始化

遍历网格

DFS 函数

3. 代码实现细节

方向数组

边界检查

访问标记

4. 优化建议

空间优化

广度优先搜索(BFS)

5. 复杂度分析

6. 总结

三、695. 岛屿的最大面积 - 力扣(LeetCode)

算法代码: 

1. 问题描述

2. 代码思路

初始化

遍历网格

DFS 函数

3. 代码实现细节

方向数组

边界检查

访问标记

4. 优化建议

空间优化

广度优先搜索(BFS)

5. 复杂度分析

6. 总结

四、130. 被围绕的区域 - 力扣(LeetCode)

算法代码:

1. 问题描述

2. 代码思路

初始化

步骤 1:标记边界及其相连的 'O'

步骤 2:还原网格

DFS 函数

3. 代码实现细节

边界遍历

DFS 的终止条件

临时标记

4. 优化建议

空间优化

广度优先搜索(BFS)

5. 复杂度分析

6. 总结

五、417. 太平洋大西洋水流问题 - 力扣(LeetCode) 

算法代码: 

1. 问题描述

2. 代码思路

初始化

步骤 1:标记能够流入太平洋的位置

步骤 2:标记能够流入大西洋的位置

步骤 3:找到同时能够流入太平洋和大西洋的位置

DFS 函数

3. 代码实现细节

边界遍历

DFS 的终止条件

结果集

4. 优化建议

空间优化

广度优先搜索(BFS)

5. 复杂度分析

6. 总结

六、529. 扫雷游戏 - 力扣(LeetCode)

 算法代码:

1. 问题描述

2. 代码思路

初始化

点击逻辑

DFS 函数

3. 代码实现细节

边界检查

递归终止条件

地雷数量统计

4. 优化建议

广度优先搜索(BFS)

空间优化

5. 复杂度分析

6. 总结

七、LCR 130. 衣橱整理 - 力扣(LeetCode)

算法代码: 

1. 问题描述

2. 代码思路

初始化

DFS 函数

检查函数

3. 代码实现细节

边界检查

数位之和计算

访问标记

4. 优化建议

广度优先搜索(BFS)

空间优化

5. 复杂度分析

6. 总结


一、733. 图像渲染 - 力扣(LeetCode)

算法代码: 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); } } } };

         这段代码实现了一个经典的 ​Flood Fill(泛洪填充)​​ 算法,用于将图像中的某个区域填充为指定颜色。以下是代码的详细思路和解释:


​代码思路

​问题描述 给定一个二维矩阵 image,表示一张图像,其中每个元素代表一个像素的颜色值。从指定的起始位置 (sr, sc) 开始,将与起始位置颜色相同的所有连通区域填充为新的颜色 color。 ​算法选择 使用 ​深度优先搜索(DFS)​​ 来遍历所有与起始位置颜色相同的像素,并将其修改为新的颜色。 ​代码结构 floodFill 函数是入口函数,负责初始化并调用 DFS。dfs 函数是递归函数,负责遍历并修改像素颜色。
​代码详解 ​1. 成员变量 int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; dx 和 dy 是方向数组,用于表示上下左右四个方向的移动。 int m, n; m 和 n 分别表示图像的行数和列数。 int prev; prev 保存起始位置 (sr, sc) 的原始颜色,用于判断哪些像素需要被填充。
​2. floodFill 函数 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; } ​参数: image:输入的图像矩阵。sr 和 sc:起始位置的行和列。color:要填充的新颜色。 ​逻辑: 如果起始位置的颜色已经是目标颜色 color,直接返回原图像(无需修改)。否则,初始化 m、n 和 prev,然后调用 dfs 函数开始填充。返回修改后的图像。
​3. dfs 函数 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); } } } ​参数: image:输入的图像矩阵。i 和 j:当前像素的位置。color:要填充的新颜色。 ​逻辑: 将当前像素 (i, j) 的颜色修改为 color。遍历上下左右四个方向: 如果相邻像素 (x, y) 在图像范围内,并且颜色等于 prev,则递归调用 dfs 继续填充。
​代码优化 ​边界检查优化 在 dfs 中,边界检查可以提前到递归调用之前,避免不必要的递归。 ​使用 BFS 如果图像较大,递归可能导致栈溢出。可以使用 ​广度优先搜索(BFS)​​ 替代 DFS,避免递归深度过大。 ​空间优化 如果需要进一步优化空间,可以修改 image 中的颜色值,避免使用额外的标记数组。
​示例运行

假设输入如下:

image = [ [1, 1, 1], [1, 1, 0], [1, 0, 1] ] sr = 1, sc = 1, color = 2

运行 floodFill 后,输出为:

[ [2, 2, 2], [2, 2, 0], [2, 0, 1] ]
​总结 这段代码通过 DFS 实现了 Flood Fill 算法,能够高效地将图像中的连通区域填充为指定颜色。代码逻辑清晰,易于理解,但需要注意递归深度的问题。如果图像较大,建议使用 BFS 或迭代 DFS 来避免栈溢出。

二、200. 岛屿数量 - 力扣(LeetCode)

算法代码:  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 && !vis[x][y] && grid[x][y] == '1') { dfs(grid, x, y); } } } };

         这段代码实现了一个经典的“岛屿数量”问题,使用了深度优先搜索(DFS)来遍历二维网格中的岛屿。下面是对代码的思路和实现细节的详细解释:

1. 问题描述

给定一个二维网格 grid,其中 '1' 表示陆地,'0' 表示水域。

岛屿是由相邻的陆地组成的,相邻指的是水平或垂直方向的相邻。

要求计算网格中岛屿的数量。

2. 代码思路 初始化

vis 是一个二维布尔数组,用于记录每个位置是否已经被访问过。

m 和 n 分别表示网格的行数和列数。

ret 用于记录岛屿的数量。

遍历网格

使用双重循环遍历整个网格。

如果当前位置是陆地(grid[i][j] == '1')且未被访问过(!vis[i][j]),则说明发现了一个新的岛屿,增加 ret 的计数,并调用 dfs 函数来标记与该陆地相连的所有陆地。

DFS 函数

dfs 函数用于递归地标记与当前陆地相连的所有陆地。

首先将当前位置标记为已访问(vis[i][j] = true)。

然后遍历当前位置的四个相邻方向(上、下、左、右),如果相邻位置是陆地且未被访问过,则递归调用 dfs。

3. 代码实现细节 方向数组

dx 和 dy 数组用于表示四个方向的移动。dx 表示行的变化,dy 表示列的变化。

例如,dx[0] = 0, dy[0] = 1 表示向右移动。

边界检查

在 dfs 函数中,检查相邻位置是否在网格范围内(x >= 0 && x < m && y >= 0 && y < n),以避免越界访问。

访问标记

使用 vis 数组来避免重复访问已经处理过的陆地。

4. 优化建议 空间优化

可以直接修改 grid 数组,将访问过的陆地标记为 '0',从而省去 vis 数组的空间开销。

修改后的 dfs 函数可以这样实现:

void dfs(vector<vector<char>>& grid, int i, int j) { grid[i][j] = '0'; // 标记为已访问 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') { dfs(grid, x, y); } } } 广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的网格。

5. 复杂度分析

时间复杂度:O(m * n),其中 m 是网格的行数,n 是网格的列数。每个位置最多被访问一次。

空间复杂度:O(m * n),主要是 vis 数组的空间开销。如果使用原地修改 grid 的方法,空间复杂度可以优化到 O(1)。

6. 总结

这段代码通过 DFS 遍历网格,有效地计算了岛屿的数量。

通过方向数组和边界检查,代码简洁且易于理解。

可以通过优化空间复杂度来进一步提升代码的效率。

三、695. 岛屿的最大面积 - 力扣(LeetCode)

算法代码:  class Solution { bool vis[51][51]; 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(); 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); } } } };

         这段代码实现了一个经典的“岛屿最大面积”问题,使用了深度优先搜索(DFS)来遍历二维网格中的岛屿,并计算每个岛屿的面积,最终返回最大岛屿的面积。下面是对代码的思路和实现细节的详细解释:


1. 问题描述

给定一个二维网格 grid,其中 1 表示陆地,0 表示水域。

岛屿是由相邻的陆地组成的,相邻指的是水平或垂直方向的相邻。

要求计算网格中最大岛屿的面积。


2. 代码思路 初始化

vis 是一个二维布尔数组,用于记录每个位置是否已经被访问过。

m 和 n 分别表示网格的行数和列数。

count 用于记录当前岛屿的面积。

ret 用于记录最大岛屿的面积。

遍历网格

使用双重循环遍历整个网格。

如果当前位置是陆地(grid[i][j] == 1)且未被访问过(!vis[i][j]),则说明发现了一个新的岛屿,初始化 count 为 0,并调用 dfs 函数来计算该岛屿的面积。

更新 ret 为当前岛屿面积和 ret 中的较大值。

DFS 函数

dfs 函数用于递归地计算与当前陆地相连的所有陆地的面积。

首先将当前位置标记为已访问(vis[i][j] = true),并增加 count 的计数。

然后遍历当前位置的四个相邻方向(上、下、左、右),如果相邻位置是陆地且未被访问过,则递归调用 dfs。


3. 代码实现细节 方向数组

dx 和 dy 数组用于表示四个方向的移动。dx 表示行的变化,dy 表示列的变化。

例如,dx[0] = 0, dy[0] = 1 表示向右移动。

边界检查

在 dfs 函数中,检查相邻位置是否在网格范围内(x >= 0 && x < m && y >= 0 && y < n),以避免越界访问。

访问标记

使用 vis 数组来避免重复访问已经处理过的陆地。


4. 优化建议 空间优化

可以直接修改 grid 数组,将访问过的陆地标记为 0,从而省去 vis 数组的空间开销。

修改后的 dfs 函数可以这样实现:

void dfs(vector<vector<int>>& grid, int i, int j) { count++; grid[i][j] = 0; // 标记为已访问 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) { dfs(grid, x, y); } } } 广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的网格。


5. 复杂度分析

时间复杂度:O(m * n),其中 m 是网格的行数,n 是网格的列数。每个位置最多被访问一次。

空间复杂度:O(m * n),主要是 vis 数组的空间开销。如果使用原地修改 grid 的方法,空间复杂度可以优化到 O(1)。


6. 总结

这段代码通过 DFS 遍历网格,有效地计算了每个岛屿的面积,并返回最大岛屿的面积。

通过方向数组和边界检查,代码简洁且易于理解。

可以通过优化空间复杂度来进一步提升代码的效率。

四、130. 被围绕的区域 - 力扣(LeetCode)

算法代码: class Solution { int dx[4] = {1, -1, 0, 0}; int dy[4] = {0, 0, 1, -1}; 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); } } } };

        这段代码实现了一个经典的“被围绕的区域”问题,使用了深度优先搜索(DFS)来标记和修改二维网格中的特定区域。下面是对代码的思路和实现细节的详细解释:


1. 问题描述

给定一个二维网格 board,其中 'O' 表示空白区域,'X' 表示障碍物。

要求将所有被 'X' 围绕的 'O' 修改为 'X'。

边界上的 'O' 以及与其相连的 'O' 不会被修改。


2. 代码思路 初始化

dx 和 dy 数组用于表示四个方向的移动(上、下、左、右)。

m 和 n 分别表示网格的行数和列数。

步骤 1:标记边界及其相连的 'O'

遍历网格的边界(第一行、最后一行、第一列、最后一列)。

如果边界上的点是 'O',则调用 dfs 函数,将其及其相连的 'O' 修改为 '.'(临时标记)。

这样做的目的是保留所有与边界相连的 'O',这些 'O' 不会被修改为 'X'。

步骤 2:还原网格

遍历整个网格:

将标记为 '.' 的点还原为 'O'。

将未被标记的 'O' 修改为 'X'(这些 'O' 是被围绕的区域)。

DFS 函数

dfs 函数用于递归地标记与当前 'O' 相连的所有 'O'。

将当前点标记为 '.'。

遍历四个方向,如果相邻点是 'O',则递归调用 dfs。


3. 代码实现细节 边界遍历

分别遍历第一行、最后一行、第一列和最后一列,确保所有边界上的 'O' 都被处理。

DFS 的终止条件

在 dfs 函数中,通过检查坐标是否在网格范围内(x >= 0 && x < m && y >= 0 && y < n)来避免越界访问。

临时标记

使用 '.' 作为临时标记,避免直接修改 'O' 导致后续判断错误。


4. 优化建议 空间优化

可以直接修改 board 数组,省去额外的标记数组。

代码已经实现了这一点,通过将边界相连的 'O' 修改为 '.',最后再还原。

广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的网格。


5. 复杂度分析

时间复杂度:O(m * n),其中 m 是网格的行数,n 是网格的列数。每个位置最多被访问一次。

空间复杂度:O(m * n),主要是递归调用栈的空间开销。如果使用 BFS,空间复杂度可以优化到 O(min(m, n))。


6. 总结

这段代码通过 DFS 遍历网格,有效地标记了与边界相连的 'O',并将其保留。

通过临时标记和还原操作,代码简洁且易于理解。

可以通过优化空间复杂度或使用 BFS 来进一步提升代码的效率。

五、417. 太平洋大西洋水流问题 - 力扣(LeetCode) 

算法代码:  class Solution { int m, n; int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; public: vector<vector<int>> pacificAtlantic(vector<vector<int>>& h) { m = h.size(), n = h[0].size(); vector<vector<bool>> pac(m, vector<bool>(n)); vector<vector<bool>> atl(m, vector<bool>(n)); // 1. 先处理 pac 洋 for (int j = 0; j < n; j++) dfs(h, 0, j, pac); for (int i = 0; i < m; i++) dfs(h, i, 0, pac); // 2. 处理 atl 洋 for (int i = 0; i < m; i++) dfs(h, i, n - 1, atl); for (int j = 0; j < n; j++) dfs(h, m - 1, j, atl); vector<vector<int>> ret; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (pac[i][j] && atl[i][j]) ret.push_back({i, j}); return ret; } void dfs(vector<vector<int>>& h, int i, int j, vector<vector<bool>>& vis) { 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] && h[x][y] >= h[i][j]) dfs(h, x, y, vis); } } };

         这段代码实现了一个经典的“太平洋大西洋水流问题”,使用了深度优先搜索(DFS)来标记能够同时流入太平洋和大西洋的区域。下面是对代码的思路和实现细节的详细解释:


1. 问题描述

给定一个二维矩阵 h,其中 h[i][j] 表示位置 (i, j) 的高度。

水流可以从高处流向低处或相同高度。

要求找到所有能够同时流入太平洋和大西洋的位置。

太平洋位于矩阵的左边界和上边界,大西洋位于矩阵的右边界和下边界。


2. 代码思路 初始化

dx 和 dy 数组用于表示四个方向的移动(上、下、左、右)。

m 和 n 分别表示矩阵的行数和列数。

pac 和 atl 是两个二维布尔数组,分别用于记录能够流入太平洋和大西洋的位置。

步骤 1:标记能够流入太平洋的位置

遍历矩阵的左边界和上边界,从这些位置开始进行 DFS,标记所有能够流入太平洋的位置。

使用 pac 数组记录这些位置。

步骤 2:标记能够流入大西洋的位置

遍历矩阵的右边界和下边界,从这些位置开始进行 DFS,标记所有能够流入大西洋的位置。

使用 atl 数组记录这些位置。

步骤 3:找到同时能够流入太平洋和大西洋的位置

遍历整个矩阵,找到同时被 pac 和 atl 标记的位置,将其加入结果集 ret。

DFS 函数

dfs 函数用于递归地标记与当前位置相连的所有能够流入海洋的位置。

将当前位置标记为已访问(vis[i][j] = true)。

遍历四个方向,如果相邻位置的高度大于等于当前位置的高度且未被访问过,则递归调用 dfs。


3. 代码实现细节 边界遍历

分别遍历左边界、上边界、右边界和下边界,确保所有可能的起点都被处理。

DFS 的终止条件

在 dfs 函数中,通过检查坐标是否在矩阵范围内(x >= 0 && x < m && y >= 0 && y < n)来避免越界访问。

通过检查高度是否满足条件(h[x][y] >= h[i][j])来确保水流能够流动。

结果集

使用 ret 数组存储所有满足条件的位置坐标。


4. 优化建议 空间优化

可以直接修改 h 数组,使用额外的标记位来记录访问状态,从而省去 pac 和 atl 数组的空间开销。

例如,可以使用 h[i][j] 的符号位来标记访问状态。

广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的矩阵。


5. 复杂度分析

时间复杂度:O(m * n),其中 m 是矩阵的行数,n 是矩阵的列数。每个位置最多被访问两次(一次来自太平洋,一次来自大西洋)。

空间复杂度:O(m * n),主要是 pac 和 atl 数组的空间开销。如果使用原地修改的方法,空间复杂度可以优化到 O(1)。


6. 总结

这段代码通过 DFS 遍历矩阵,有效地标记了能够流入太平洋和大西洋的位置。

通过分别处理两个海洋的边界,代码逻辑清晰且易于理解。

可以通过优化空间复杂度或使用 BFS 来进一步提升代码的效率。

六、529. 扫雷游戏 - 力扣(LeetCode)

 算法代码: class Solution { int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1}; int dy[8] = {1, -1, 0, 0, 1, -1, 1, -1}; int m, n; public: vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) { m = board.size(), n = board[0].size(); int x = click[0], y = click[1]; if (board[x][y] == 'M') // 直接点到地雷 { board[x][y] = 'X'; return board; } dfs(board, x, y); return board; } void dfs(vector<vector<char>>& board, int i, int j) { // 统计⼀下周围的地雷个数 int count = 0; for (int k = 0; k < 8; k++) { int x = i + dx[k], y = j + dy[k]; if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M') { count++; } } if (count) // 周围有地雷 { board[i][j] = count + '0'; return; } else // 周围没有地雷 { board[i][j] = 'B'; for (int k = 0; k < 8; k++) { int x = i + dx[k], y = j + dy[k]; if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E') { dfs(board, x, y); } } } } };

        这段代码实现了一个经典的“扫雷游戏”问题,使用了深度优先搜索(DFS)来模拟点击方块后的游戏逻辑。下面是对代码的思路和实现细节的详细解释:


1. 问题描述

给定一个二维矩阵 board,表示扫雷游戏的初始状态:

'M' 表示未挖出的地雷。

'E' 表示未挖出的空白方块。

'B' 表示已挖出的空白方块,且周围没有地雷。

数字 '1' 到 '8' 表示已挖出的方块,且周围有对应数量的地雷。

'X' 表示已挖出的地雷。

给定一个点击位置 click,模拟点击后的游戏状态。


2. 代码思路 初始化

dx 和 dy 数组用于表示八个方向的移动(上、下、左、右、左上、右上、左下、右下)。

m 和 n 分别表示矩阵的行数和列数。

点击逻辑

如果点击的位置是地雷(board[x][y] == 'M'),则将其修改为 'X',表示游戏结束。

否则,调用 dfs 函数处理点击的方块。

DFS 函数

统计周围地雷数量:

遍历当前位置的八个方向,统计周围地雷的数量 count。

处理当前方块:

如果周围有地雷(count > 0),则将当前方块修改为地雷数量(count + '0')。

如果周围没有地雷(count == 0),则将当前方块修改为 'B',并递归处理周围的未挖出方块('E')。


3. 代码实现细节 边界检查

在 dfs 函数中,通过检查坐标是否在矩阵范围内(x >= 0 && x < m && y >= 0 && y < n)来避免越界访问。

递归终止条件

如果当前方块是 'E',则继续递归处理。

如果当前方块是 'M' 或其他非 'E' 的状态,则停止递归。

地雷数量统计

使用 count 变量统计周围地雷的数量,并将其转换为字符(count + '0')以便更新方块状态。


4. 优化建议 广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的矩阵。

空间优化

代码已经直接修改了 board 数组,没有使用额外的空间,空间复杂度为 O(1)。


5. 复杂度分析

时间复杂度:O(m * n),其中 m 是矩阵的行数,n 是矩阵的列数。每个位置最多被访问一次。

空间复杂度:O(m * n),主要是递归调用栈的空间开销。如果使用 BFS,空间复杂度可以优化到 O(min(m, n))。


6. 总结

这段代码通过 DFS 遍历矩阵,模拟了扫雷游戏的点击逻辑。

通过统计周围地雷数量和递归处理空白方块,代码逻辑清晰且易于理解。

可以通过使用 BFS 或优化递归深度来进一步提升代码的效率。

七、LCR 130. 衣橱整理 - 力扣(LeetCode)

算法代码:  class Solution { int m, n, k; bool vis[101][101]; int ret; int dx[4] = {0, 0, -1, 1}; int dy[4] = {1, -1, 0, 0}; public: int wardrobeFinishing(int _m, int _n, int _k) { m = _m, n = _n, k = _k; dfs(0, 0); return ret; } void dfs(int i, int j) { ret++; 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] && check(x, y)) dfs(x, y); } } bool check(int i, int j) { int tmp = 0; while (i) { tmp += i % 10; i /= 10; } while (j) { tmp += j % 10; j /= 10; } return tmp <= k; } };

        这段代码实现了一个经典的“机器人运动范围”问题,使用了深度优先搜索(DFS)来计算机器人能够到达的格子数量。下面是对代码的思路和实现细节的详细解释:


1. 问题描述

给定一个 m x n 的网格,机器人从 (0, 0) 出发。

机器人每次可以向上、下、左、右移动一格。

机器人不能进入行坐标和列坐标的数位之和大于 k 的格子。

要求计算机器人能够到达多少个格子。


2. 代码思路 初始化

m 和 n 分别表示网格的行数和列数。

k 表示数位之和的上限。

vis 是一个二维布尔数组,用于记录每个位置是否已经被访问过。

ret 用于记录机器人能够到达的格子数量。

dx 和 dy 数组用于表示四个方向的移动(上、下、左、右)。

DFS 函数

从起点 (0, 0) 开始调用 dfs 函数。

在 dfs 函数中:

将当前位置标记为已访问(vis[i][j] = true),并增加 ret 的计数。

遍历四个方向,如果相邻位置满足以下条件,则递归调用 dfs:

在网格范围内(x >= 0 && x < m && y >= 0 && y < n)。

未被访问过(!vis[x][y])。

数位之和不超过 k(check(x, y) 返回 true)。

检查函数

check 函数用于计算位置 (i, j) 的行坐标和列坐标的数位之和。

如果数位之和不超过 k,则返回 true,否则返回 false。


3. 代码实现细节 边界检查

在 dfs 函数中,通过检查坐标是否在网格范围内(x >= 0 && x < m && y >= 0 && y < n)来避免越界访问。

数位之和计算

在 check 函数中,通过循环取模和除法操作计算行坐标和列坐标的数位之和。

访问标记

使用 vis 数组来避免重复访问已经处理过的格子。


4. 优化建议 广度优先搜索(BFS)

除了 DFS,还可以使用 BFS 来解决这个问题。BFS 使用队列来实现,适合处理较大的网格。

空间优化

可以直接修改 vis 数组,省去额外的空间开销。


5. 复杂度分析

时间复杂度:O(m * n),其中 m 是网格的行数,n 是网格的列数。每个位置最多被访问一次。

空间复杂度:O(m * n),主要是 vis 数组的空间开销。


6. 总结

这段代码通过 DFS 遍历网格,有效地计算了机器人能够到达的格子数量。

通过数位之和的限制和访问标记,代码逻辑清晰且易于理解。

可以通过优化空间复杂度或使用 BFS 来进一步提升代码的效率。

标签:

FloodFill算法(典型算法思想)——OJ例题算法解析思路由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“FloodFill算法(典型算法思想)——OJ例题算法解析思路