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. 返回结果

    • 一旦找到连接两个岛屿的最短路径,立即返回该路径长度。
相关推荐
拓端研究室1 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法
随缘而动,随遇而安3 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
IT古董4 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
Alfred king7 小时前
面试150 生命游戏
leetcode·游戏·面试·数组
水木兰亭7 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
June bug8 小时前
【软考中级·软件评测师】下午题·面向对象测试之架构考点全析:分层、分布式、微内核与事件驱动
经验分享·分布式·职场和发展·架构·学习方法·测试·软考
Jess078 小时前
插入排序的简单介绍
数据结构·算法·排序算法
老一岁8 小时前
选择排序算法详解
数据结构·算法·排序算法
xindafu8 小时前
代码随想录算法训练营第四十二天|动态规划part9
算法·动态规划
xindafu8 小时前
代码随想录算法训练营第四十五天|动态规划part12
算法·动态规划