多源BFS(典型算法思想)—— OJ例题算法解析思路

devtools/2025/2/24 12:46:17/

目录

一、542. 01 矩阵 - 力扣(LeetCode)

算法代码: 

代码逻辑思路

数据结构初始化

步骤一:队列初始化

步骤二:广度优先搜索

返回结果

关键点总结

广度优先搜索(BFS)

访问标记

复杂度分析

二、1020. 飞地的数量 - 力扣(LeetCode) 

算法代码: 

代码逻辑思路

数据结构初始化

步骤一:将边界上的陆地单元格加入队列

步骤二:多源 BFS 扩展

步骤三:统计被水包围的陆地单元格数量

关键点总结

多源 BFS

访问标记

复杂度分析

三、1765. 地图中的最高点 - 力扣(LeetCode)

算法代码: 

代码逻辑思路

关键点总结

四、1162. 地图分析 - 力扣(LeetCode)

算法代码: 

代码逻辑思路

关键点总结


一、542. 01 矩阵 - 力扣(LeetCode)

算法代码: 

class Solution {int dx[4] = {0, 0, 1, -1}; // 四个方向的 x 偏移量int dy[4] = {1, -1, 0, 0}; // 四个方向的 y 偏移量public:vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {int m = mat.size(), n = mat[0].size();// dist[i][j] == -1 表示没有搜索过// dist[i][j] != -1 表示最短距离vector<vector<int>> dist(m, vector<int>(n, -1)); // 初始化距离矩阵为 -1queue<pair<int, int>> q; // BFS 队列// 1. 把所有的源点加入到队列中for (int i = 0; i < m; i++)for (int j = 0; j < n; j++)if (mat[i][j] == 0) { // 找到 0 的位置q.push({i, j}); // 入队dist[i][j] = 0; // 距离为 0}// 2. 一层一层的往外扩展while (q.size()) {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 && dist[x][y] == -1) {dist[x][y] = dist[a][b] + 1; // 更新距离q.push({x, y}); // 入队}}}return dist; // 返回结果矩阵}
};

代码逻辑思路

  1. 数据结构初始化

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

    • 创建一个 dist 矩阵,用于存储每个单元格到最近零的距离,初始化为 -1,表示尚未被搜索过。

    • 使用一个队列 q 来实现广度优先搜索(BFS)。

  2. 步骤一:队列初始化

    • 遍历整个矩阵 mat,将所有的 0 的位置(源点)加入队列 q,并将对应的 dist 值设为 0,因为从 0 到 0 的距离为 0

  3. 步骤二:广度优先搜索

    • 使用 BFS 从所有的 0 出发,逐层向外扩展。

    • 在每次循环中,取出队列的前一个元素 (a, b),表示当前正在处理的位置。

    • 遍历四个方向(上下左右),计算 (x, y) 的新位置。

    • 检查新位置是否在矩阵范围内,且 dist[x][y] 为 -1(表示尚未访问过):

      • 如果是,则将 dist[x][y] 更新为 dist[a][b] + 1,表示新位置到最近 0 的距离。

      • 把新位置 (x, y) 加入队列 q

  4. 返回结果

    • 当队列为空时,所有位置的最短距离都已经计算完毕,返回 dist 矩阵。

关键点总结

  1. 广度优先搜索(BFS)

    • BFS 是解决最短路径问题的经典方法,适合用于从多个源点扩展到其它点的场景。

    • 通过从所有的 0 开始,同时向外扩展,确保每个位置的最短路径都能被正确计算。

  2. 访问标记

    • 使用 dist 数组来标记每个位置是否已被访问,并存储到最近 0 的距离。

  3. 复杂度分析

    • 时间复杂度为 O(m * n),因为每个位置最多被访问一次。

    • 空间复杂度为 O(m * n),用于存储 dist 矩阵和 BFS 队列。

这种方法有效且高效,适用于计算二维矩阵中元素到最近目标元素的距离问题。

二、1020. 飞地的数量 - 力扣(LeetCode) 

算法代码: 

class Solution {int dx[4] = {0, 0, 1, -1}; // 四个方向的 x 偏移量int dy[4] = {1, -1, 0, 0}; // 四个方向的 y 偏移量public:int numEnclaves(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<vector<bool>> vis(m, vector<bool>(n)); // 访问标记queue<pair<int, int>> q; // BFS 队列// 1. 把边上的 1 加入到队列中for (int i = 0; i < m; i++)for (int j = 0; j < n; j++)if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {if (grid[i][j] == 1) { // 找到边界上的陆地q.push({i, j}); // 入队vis[i][j] = true; // 标记为已访问}}// 2. 多源 BFS 扩展while (q.size()) {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]) {vis[x][y] = true; // 标记为已访问q.push({x, y}); // 入队}}}// 3. 统计结果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++; // 增加计数return ret; // 返回结果}
};

代码逻辑思路

  1. 数据结构初始化

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

    • 创建一个 vis 矩阵,用于记录每个单元格是否被访问过。

    • 使用一个队列 q 来进行 BFS。

  2. 步骤一:将边界上的陆地单元格加入队列

    • 遍历整个网格 grid,在边界(第一行、最后一行、第一列、最后一列)中寻找值为 1 的单元格。

    • 如果找到这样的单元格,将它加入队列 q,并标记为已访问。

  3. 步骤二:多源 BFS 扩展

    • 使用 BFS 从队列中的所有陆地单元格开始,逐层向外扩展。

    • 在每次循环中,取出队列的前一个元素 (a, b),表示当前正在处理的位置。

    • 遍历四个方向(上下左右),计算新位置 (x, y)

    • 检查新位置是否在矩阵范围内,且值为 1,并且未被访问:

      • 如果满足条件,标记该位置为已访问,并将其加入队列 q

  4. 步骤三:统计被水包围的陆地单元格数量

    • 遍历整个网格 grid,统计值为 1 并且未被访问的单元格的数量,表示这些单元格是被水包围的陆地单元格。

    • 返回这个计数作为结果。

关键点总结

  1. 多源 BFS

    • 从所有边界的陆地单元格开始,同时向内扩展,确保能够覆盖所有与边界相连的陆地。

    • BFS 确保每个陆地单元格仅被访问一次。

  2. 访问标记

    • 使用 vis 数组来标记每个单元格是否已被访问,避免重复计算。

  3. 复杂度分析

    • 时间复杂度为 O(m * n),因为每个单元格最多被访问一次。

    • 空间复杂度为 O(m * n),用于存储访问标记和 BFS 队列。

这种方法有效且高效,适用于计算被水包围的陆地单元格的数量。

三、1765. 地图中的最高点 - 力扣(LeetCode)

算法代码: 

class Solution {int dx[4] = {0, 0, 1, -1}; // 四个方向的 x 偏移量int dy[4] = {1, -1, 0, 0}; // 四个方向的 y 偏移量public:vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {int m = isWater.size(), n = isWater[0].size();vector<vector<int>> dist(m, vector<int>(n, -1)); // 初始化高度矩阵为 -1queue<pair<int, int>> q; // BFS 队列// 1. 把所有的源点加入到队列里面for (int i = 0; i < m; i++)for (int j = 0; j < n; j++)if (isWater[i][j]) { // 找到水域单元格dist[i][j] = 0; // 高度设为 0q.push({i, j}); // 入队}// 2. 多源 BFS 扩展while (q.size()) {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 && dist[x][y] == -1) {dist[x][y] = dist[a][b] + 1; // 更新高度q.push({x, y}); // 入队}}}return dist; // 返回结果矩阵}
};

代码逻辑思路

  1. 数据结构初始化

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

    • 创建一个 dist 矩阵,用于存储每个单元格的高度,初始值为 -1,表示尚未计算。

    • 使用一个队列 q 来实现 BFS。

  2. 步骤一:将所有水域单元格加入队列

    • 遍历整个矩阵 isWater,找到所有值为 1 的单元格(水域)。

    • 将这些水域单元格的对应位置在 dist 矩阵中设置为 0,并将其加入队列 q

  3. 步骤二:多源 BFS 扩展

    • 使用 BFS 从队列中的所有水域单元格开始,逐层向外扩展。

    • 在每次循环中,取出队列的前一个元素 (a, b),表示当前正在处理的位置。

    • 遍历四个方向(上下左右),计算新位置 (x, y)

    • 检查新位置是否在矩阵范围内,且 dist[x][y] 为 -1(表示尚未计算):

      • 如果满足条件,则更新 dist[x][y] 为 dist[a][b] + 1,表示新位置到最近水域的距离。

      • 将新位置 (x, y) 加入队列 q

  4. 返回结果

    • 当队列为空时,所有位置的高度都已经计算完毕,返回 dist 矩阵。

关键点总结

  1. 多源 BFS

    • BFS 从所有水域单元格同时开始,同时向内扩展,确保所有陆地单元格的高度能够被正确计算。

    • BFS 能够保证每个陆地单元格的高度是距离最近水域单元格的最短距离。

  2. 访问标记

    • 使用 dist 数组来标记每个单元格的高度,并避免重复计算。

  3. 复杂度分析

    • 时间复杂度为 O(m * n),每个单元格最多被访问一次。

    • 空间复杂度为 O(m * n),用于存储高度矩阵和 BFS 队列。

        这种方法有效且高效,适用于计算二维矩阵中每个单元格的高度,特别是在有障碍物(如水域)时。

四、1162. 地图分析 - 力扣(LeetCode)

算法代码: 

class Solution {int dx[4] = {0, 0, 1, -1}; // 四个方向的 x 偏移量int dy[4] = {1, -1, 0, 0}; // 四个方向的 y 偏移量public:int maxDistance(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<vector<int>> dist(m, vector<int>(n, -1)); // 初始化距离矩阵为 -1queue<pair<int, int>> q; // BFS 队列// 1. 把所有陆地单元格加入到队列里面for (int i = 0; i < m; i++)for (int j = 0; j < n; j++)if (grid[i][j]) { // 判断是否为陆地dist[i][j] = 0; // 陆地的距离为 0q.push({i, j}); // 入队}int ret = -1; // 最大距离初始化为 -1// 2. 多源 BFS 扩展while (q.size()) {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 && dist[x][y] == -1) {dist[x][y] = dist[a][b] + 1; // 更新距离q.push({x, y}); // 入队ret = max(ret, dist[x][y]); // 更新最大距离}}}return ret; // 返回最大距离}
};

代码逻辑思路

  1. 数据结构初始化

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

    • 创建一个 dist 矩阵,用于存储每个单元格的距离,初始值为 -1,表示尚未计算。

    • 使用一个队列 q 来实现 BFS。

  2. 步骤一:将所有陆地单元格加入队列

    • 遍历整个网格 grid,找到所有值为 1 的单元格(陆地)。

    • 将这些陆地单元格的对应位置在 dist 矩阵中设置为 0,并将它们加入队列 q

  3. 步骤二:多源 BFS 扩展

    • 使用 BFS 从队列中的所有陆地单元格开始,逐层向外扩展。

    • 在每次循环中,取出队列的前一个元素 (a, b),表示当前正在处理的位置。

    • 遍历四个方向(上下左右),计算新位置 (x, y)

    • 检查新位置是否在矩阵范围内,且 dist[x][y] 为 -1(表示尚未计算):

      • 如果满足条件,则更新 dist[x][y] 为 dist[a][b] + 1,表示新位置到最近水域的距离。

      • 将新位置 (x, y) 加入队列 q

      • 在更新后,更新 ret 为当前最大距离。

  4. 返回结果

    • 当队列为空时,所有位置的最大距离都已经计算完毕,返回 ret

关键点总结

  1. 多源 BFS

    • 从所有陆地单元格同时开始,BFS 确保所有水域单元格的最大距离能够被正确计算。

    • BFS 的逐层扩展特性确保了每个单元格到最近水域单元格的距离是最短的。

  2. 访问标记

    • 使用 dist 数组来标记每个单元格的距离,并避免重复计算。

  3. 复杂度分析

    • 时间复杂度为 O(m * n),每个单元格最多被访问一次。

    • 空间复杂度为 O(m * n),用于存储距离矩阵和 BFS 队列。

这种方法有效且高效,适用于计算二维矩阵中每个陆地单元格到最近水域单元格的最大距离。


http://www.ppmy.cn/devtools/161363.html

相关文章

如何将MySQL数据库迁移至阿里云

将 MySQL 数据库迁移至阿里云可以通过几种不同的方法&#xff0c;具体选择哪种方式取决于你的数据库大小、数据复杂性以及对迁移速度的需求。阿里云提供了多种迁移工具和服务&#xff0c;本文将为你介绍几种常见的方法。 方法一&#xff1a;使用 阿里云数据库迁移服务 (DTS) 阿…

挪车小程序挪车二维码php+uniapp

一款基于FastAdminThinkPHP开发的匿名通知车主挪车微信小程序&#xff0c;采用匿名通话的方式&#xff0c;用户只能在有效期内拨打车主电话&#xff0c;过期失效&#xff0c;从而保护车主和用户隐私。提供微信小程序端和服务端源码&#xff0c;支持私有化部署。 更新日志 V1.0…

基于RISC-V内核完全自主可控国产化MCU芯片

国科安芯MCU芯片采用开放、灵活的RISC-V指令集架构&#xff0c;RISC-V的开源特性不仅大幅降低研发成本&#xff0c;更赋予芯片设计高度定制化能力。例如&#xff0c;国科安芯的AS32S601抗辐照MCU基于32位RV32IMZicsr指令集&#xff0c;主频达180MHz&#xff0c;内置2MB Flash与…

小波变换背景预测matlab和python样例

小波变换使用matlab和python 注意1d和2d的函数区别。注意默认参数问题。最终三个版本结果能够对齐。 matlab load(wave_in.mat)% res: image of 1536 x 1536 th1; dlevel7; wavenamedb6;[m,n] wavedec2(res, dlevel, wavename);vec zeros(size(m)); vec(1:n(1)*n(1)*1) m…

AI汽车新风向:「死磕」AI底盘,引爆线控底盘新增长拐点

2025开年&#xff0c;DeepSeek火爆出圈&#xff0c;包括吉利、东风汽车、上汽、广汽、长城、长安、比亚迪等车企相继官宣接入&#xff0c;掀起了“AI定义汽车”浪潮。 而这股最火的AI汽车热潮&#xff0c;除了深度赋能智能座舱、智能驾驶等AI竞争更白热化的细分场景&#xff0…

qt.qpa.fonts: Unable to open default EUDC font: “EUDC.TTE“

参考笔记: qt.qpa.fonts: Unable to open default EUDC font: “C:\WINDOWS\FONTS\EUDC.TTE” 参考笔记: Qt错误: qt.qpa.fonts:无法打开默认EUDC字体&#xff1a;"C:\WINDOWS\FONTS\EUDC.TTE“ QT写的软件, 启动时总会打印一条警告 qt.qpa.fonts: Unable to open defaul…

jvm中各个参数的理解

MEMORY - MANAGERS 定义 MEMORY - MANAGERS即内存管理器&#xff0c;它是操作系统或软件系统中负责管理计算机内存资源的组件。从本质上来说&#xff0c;它是一种软件机制&#xff0c;旨在协调计算机系统中内存的分配、使用和回收等操作&#xff0c;确保系统能够高效、稳定地…

机器学习,我们主要学习什么?

机器学习的发展历程 机器学习的发展历程&#xff0c;大致分为以下几个阶段&#xff1a; 1. 起源与早期探索&#xff08;20世纪40年代-60年代&#xff09; 1949年&#xff1a;Hebb提出了基于神经心理学的学习机制&#xff0c;开启了机器学习的先河1950年代&#xff1a;机器学习的…