LeetCode-934. 最短的桥

1、题目描述:

给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。

是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid恰好存在两座岛

你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛

返回必须翻转的 0 的最小数目。

示例 1:

复制代码
输入:grid = [[0,1],
              [1,0]]
输出:1

示例 2:

复制代码
输入:grid = [[0,1,0],
              [0,0,0],
              [0,0,1]]
输出:2

示例 3:

复制代码
输入:grid = [[1,1,1,1,1],
              [1,0,0,0,1],
              [1,0,1,0,1],
              [1,0,0,0,1],
              [1,1,1,1,1]]
输出:1

提示:

  • n == grid.length == grid[i].length
  • 2 <= n <= 100
  • grid[i][j]01
  • grid 中恰有两个岛

2、代码:

cpp 复制代码
/*
 * @file shortest_bridge.cpp
 * @brief 在二进制矩阵中找到连接两个岛屿的最短路径
 * 
 * 给定一个 n x n 的二进制矩阵 grid,其中 1 表示陆地,0 表示水域。
 * 岛屿是由四面相连的 1 组成的组。假设矩阵中有且仅有两个岛屿,
 * 需要找到连接两个岛屿的最短桥(即翻转最少数量的0使两个岛屿相连)。
 * 
 * 实现思路:
 *  1. 使用BFS标记第一个岛屿的所有单元格(标记为2)
 *  2. 从第一个岛屿的所有边界开始进行多源BFS扩展
 *  3. 当遇到第二个岛屿(值为1的单元格)时,返回扩展的步数
 * 
 */

#include <vector>
#include <queue>

using namespace std;

class Solution {
public:
    int shortestBridge(vector<vector<int>>& grid) {
        int n = grid.size();
        // 定义四个移动方向:上、下、左、右
        vector<vector<int>> dirs = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
        // 主队列:用于后续的多源BFS扩展
        queue<pair<int, int>> q;

        // 步骤1: 找到并标记第一个岛屿
        bool found = false; // 标记是否已找到第一个岛屿
        for (int i = 0; i < n && !found; ++i) {
            for (int j = 0; j < n && !found; ++j) {
                if (grid[i][j] == 1) {  // 发现第一个岛屿的起始点
                    // 使用BFS标记整个岛屿
                    queue<pair<int, int>> islandQ; // 岛屿内部BFS专用队列
                    islandQ.push({ i, j });
                    grid[i][j] = 2;     // 将起始点标记为2(表示属于第一个岛屿)
                    q.push({ i, j });   // 同时加入主队列(作为多源BFS的起点)
                    
                    // BFS遍历并标记第一个岛屿的所有单元格
                    while (!islandQ.empty()) {
                        auto [x, y] = islandQ.front();
                        islandQ.pop();
                        // 检查四个方向
                        for (auto& dir : dirs) {
                            int nx = x + dir[0], ny = y + dir[1];
                            // 检查新位置是否在网格内且属于第一个岛屿(值为1)
                            if (nx >= 0 && ny >= 0 && nx < n && ny < n && grid[nx][ny] == 1) {
                                grid[nx][ny] = 2;   // 标记为属于第一个岛屿
                                islandQ.push({ nx, ny }); // 加入岛屿BFS队列
                                q.push({ nx, ny }); // 加入主队列(作为扩展起点)
                            }
                        }
                    }
                    found = true; // 标记第一个岛屿已处理完成
                }
            }
        }

        // 步骤2: 从第一个岛屿边界开始进行多源BFS扩展
        int step = 0; // 记录扩展的步数(即桥的长度)
        while (!q.empty()) {
            int size = q.size(); // 当前层的节点数量
            // 遍历当前层的所有节点
            for (int i = 0; i < size; ++i) {
                auto [x, y] = q.front();
                q.pop();
                // 向四个方向扩展
                for (auto& dir : dirs) {
                    int nx = x + dir[0], ny = y + dir[1];
                    // 检查新位置是否在网格内
                    if (nx >= 0 && ny >= 0 && nx < n && ny < n) {
                        if (grid[nx][ny] == 1) {
                            // 找到第二个岛屿,返回当前步数(即桥的最小长度)
                            return step;
                        }
                        else if (grid[nx][ny] == 0) {
                            // 遇到水域,标记为已访问(避免重复处理)
                            grid[nx][ny] = 2;
                            // 加入队列继续扩展
                            q.push({ nx, ny });
                        }
                    }
                }
            }
            step++; // 完成一层扩展,步数增加
        }

        return -1; // 理论上不会执行(因为保证有两个岛屿)
    }
};

3、解题思路:

  1. 识别第一个岛屿

    • 遍历矩阵,找到第一个值为 1 的点,使用 BFS 或 DFS 遍历其所有相连的 1,标记为第一个岛屿。
    • 在这个过程中,可以使用一个 dist 数组来记录每个点的距离,初始岛屿的点距离为 0
  2. BFS 扩展第一个岛屿

    • 从第一个岛屿的所有点出发,进行 BFS 扩展,逐步向外探索。
    • 每次扩展一个 0,将其标记为已访问,并记录当前扩展的步数。
    • 当扩展过程中遇到另一个岛屿的 1 时,此时的步数即为需要转换的最小水域数量。
  3. 返回结果

    • 一旦找到连接两个岛屿的最短路径,立即返回该路径长度。
相关推荐
点云SLAM11 分钟前
PyTorch 中.backward() 详解使用
人工智能·pytorch·python·深度学习·算法·机器学习·机器人
only-qi40 分钟前
146. LRU 缓存
java·算法·缓存
梁辰兴2 小时前
数据结构:排序
数据结构·算法·排序算法·c·插入排序·排序·交换排序
Lris-KK2 小时前
【Leetcode】高频SQL基础题--1731.每位经理的下属员工数量
sql·leetcode
野犬寒鸦2 小时前
力扣hot100:搜索二维矩阵 II(常见误区与高效解法详解)(240)
java·数据结构·算法·leetcode·面试
菜鸟得菜2 小时前
leecode kadane算法 解决数组中子数组的最大和,以及环形数组连续子数组的最大和问题
数据结构·算法·leetcode
楼田莉子3 小时前
C++算法专题学习——分治
数据结构·c++·学习·算法·leetcode·排序算法
一支鱼4 小时前
leetcode常用解题方案总结
前端·算法·leetcode
ulias2124 小时前
各种背包问题简述
数据结构·c++·算法·动态规划
m0_570466414 小时前
代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
java·开发语言·算法