news 2026/3/11 7:09:02

算法题 最短的桥

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法题 最短的桥

934. 最短的桥

问题描述

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

保证恰好有两座岛(即两个由1组成的连通分量)。

你可以将0变成1来建造桥梁,使得两座岛连接起来。

返回需要建造的最短桥梁的长度(即最少需要翻转多少个0)。

注意:在二维网格中,连通性是指上下左右四个方向。

示例

输入: grid = [[0,1],[1,0]] 输出: 1 解释: 翻转 grid[0][0] 或 grid[1][1] 即可连接两座岛。 输入: grid = [[0,1,0],[0,0,0],[0,0,1]] 输出: 2 解释: 翻转 grid[0][2] 和 grid[1][2],或者翻转 grid[1][0] 和 grid[2][0]。 输入: 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 解释: 中间的0只需要翻转一个即可连接。

算法思路

多源BFS

步骤

  1. 找到第一座岛:使用DFS或BFS遍历找到其中一个连通分量(岛)
  2. 标记第一座岛:将第一座岛的所有位置标记为特殊值(如2),并将所有边界位置加入BFS队列
  3. 多源BFS扩展:从第一座岛的所有位置同时开始BFS,寻找第二座岛
  4. 返回距离:当BFS第一次遇到值为1的位置时,当前的BFS层数就是最短桥梁长度

代码实现

方法一:DFS + 多源BFS

classSolution{privatestaticfinalint[][]DIRECTIONS={{-1,0},{1,0},{0,-1},{0,1}};/** * 找到连接两座岛的最短桥梁长度 * * @param grid n x n 的二进制矩阵 * @return 最短桥梁长度 */publicintshortestBridge(int[][]grid){intn=grid.length;booleanfoundFirstIsland=false;Queue<int[]>queue=newLinkedList<>();// 1: 找到第一座岛并标记for(inti=0;i<n&&!foundFirstIsland;i++){for(intj=0;j<n&&!foundFirstIsland;j++){if(grid[i][j]==1){// 使用DFS标记第一座岛为2,并将所有位置加入BFS队列dfsMarkIsland(grid,i,j,queue);foundFirstIsland=true;}}}// 2: 多源BFS寻找第二座岛intbridgeLength=0;while(!queue.isEmpty()){intsize=queue.size();// 处理当前BFS层的所有节点for(inti=0;i<size;i++){int[]current=queue.poll();introw=current[0];intcol=current[1];// 探索四个方向for(int[]dir:DIRECTIONS){intnewRow=row+dir[0];intnewCol=col+dir[1];// 边界检查if(newRow>=0&&newRow<n&&newCol>=0&&newCol<n){if(grid[newRow][newCol]==1){// 找到第二座岛,返回当前桥梁长度returnbridgeLength;}elseif(grid[newRow][newCol]==0){// 水域,标记为已访问并加入队列grid[newRow][newCol]=2;queue.offer(newint[]{newRow,newCol});}// 如果是2(第一座岛),跳过}}}bridgeLength++;}return-1;//}/** * DFS标记第一座岛为2,并将所有位置加入BFS队列 */privatevoiddfsMarkIsland(int[][]grid,introw,intcol,Queue<int[]>queue){intn=grid.length;// 边界检查和访问检查if(row<0||row>=n||col<0||col>=n||grid[row][col]!=1){return;}// 标记为第一座岛(2)并加入BFS队列grid[row][col]=2;queue.offer(newint[]{row,col});// 递归标记相邻的陆地for(int[]dir:DIRECTIONS){dfsMarkIsland(grid,row+dir[0],col+dir[1],queue);}}}

方法二:BFS + 多源BFS

classSolution{privatestaticfinalint[][]DIRECTIONS={{-1,0},{1,0},{0,-1},{0,1}};publicintshortestBridge(int[][]grid){intn=grid.length;Queue<int[]>queue=newLinkedList<>();booleanfoundFirstIsland=false;// 使用BFS找到并标记第一座岛for(inti=0;i<n&&!foundFirstIsland;i++){for(intj=0;j<n&&!foundFirstIsland;j++){if(grid[i][j]==1){bfsMarkIsland(grid,i,j,queue);foundFirstIsland=true;}}}// 多源BFSreturnmultiSourceBFS(grid,queue);}privatevoidbfsMarkIsland(int[][]grid,intstartRow,intstartCol,Queue<int[]>queue){intn=grid.length;Queue<int[]>islandQueue=newLinkedList<>();islandQueue.offer(newint[]{startRow,startCol});grid[startRow][startCol]=2;queue.offer(newint[]{startRow,startCol});while(!islandQueue.isEmpty()){int[]current=islandQueue.poll();introw=current[0];intcol=current[1];for(int[]dir:DIRECTIONS){intnewRow=row+dir[0];intnewCol=col+dir[1];if(newRow>=0&&newRow<n&&newCol>=0&&newCol<n&&grid[newRow][newCol]==1){grid[newRow][newCol]=2;islandQueue.offer(newint[]{newRow,newCol});queue.offer(newint[]{newRow,newCol});}}}}privateintmultiSourceBFS(int[][]grid,Queue<int[]>queue){intn=grid.length;intbridgeLength=0;while(!queue.isEmpty()){intsize=queue.size();for(inti=0;i<size;i++){int[]current=queue.poll();introw=current[0];intcol=current[1];for(int[]dir:DIRECTIONS){intnewRow=row+dir[0];intnewCol=col+dir[1];if(newRow>=0&&newRow<n&&newCol>=0&&newCol<n){if(grid[newRow][newCol]==1){returnbridgeLength;}elseif(grid[newRow][newCol]==0){grid[newRow][newCol]=2;queue.offer(newint[]{newRow,newCol});}}}}bridgeLength++;}return-1;}}

算法分析

  • 时间复杂度:O(n²)
    • DFS/BFS标记第一座岛:O(n²)
    • 多源BFS扩展:O(n²)
  • 空间复杂度:O(n²)
    • 队列在最坏情况下可能存储O(n²)个元素
    • 递归DFS的栈深度最坏情况下也是O(n²)

算法过程

输入:grid = [[0,1],[1,0]]

  1. 找到第一座岛

    • 在(0,1)找到第一个1
    • DFS标记第一座岛:只有(0,1),标记为2
    • BFS队列:[(0,1)]
  2. 多源BFS

    • 层0:队列[(0,1)]
    • 探索邻居:(0,0)=0→标记为2加入队列,(1,1)=0→标记为2加入队列,(0,2)和(-1,1)越界
    • 层1:队列[(0,0), (1,1)]
    • 从(1,1)探索(1,0)=1→找到第二座岛!
    • 返回桥梁长度 = 1

输入:grid = [[0,1,0],[0,0,0],[0,0,1]]

  1. 标记第一座岛:(0,1)标记为2,队列[(0,1)]
  2. BFS层0:探索(0,0)=0、(0,2)=0、(1,1)=0 → 队列[(0,0),(0,2),(1,1)]
  3. BFS层1:从(0,2)探索(1,2)=0;从(1,1)探索(1,0)=0、(1,2)=0、(2,1)=0 → 队列包含这些位置
  4. BFS层2:从(1,2)探索(2,2)=1 → 找到第二座岛,返回2

测试用例

publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:最小情况int[][]grid1={{0,1},{1,0}};System.out.println("Test 1: "+solution.shortestBridge(grid1));// 1// 测试用例2:标准示例int[][]grid2={{0,1,0},{0,0,0},{0,0,1}};System.out.println("Test 2: "+solution.shortestBridge(grid2));// 2// 测试用例3:环形岛屿int[][]grid3={{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}};System.out.println("Test 3: "+solution.shortestBridge(grid3));// 1// 测试用例4:大岛屿int[][]grid4={{1,1,0,0,0},{1,0,0,0,0},{0,0,0,0,1},{0,0,0,1,1},{0,0,0,1,1}};System.out.println("Test 4: "+solution.shortestBridge(grid4));// 3// 测试用例5:相邻岛屿int[][]grid5={{1,0,1},{0,0,0},{0,0,0}};System.out.println("Test 5: "+solution.shortestBridge(grid5));// 1// 测试用例6:单格岛屿int[][]grid6={{1,0,0},{0,0,0},{0,0,1}};System.out.println("Test 6: "+solution.shortestBridge(grid6));// 3// 测试用例7:复杂形状int[][]grid7={{0,0,0,0,0,0},{0,1,1,0,0,0},{0,1,0,0,0,0},{0,0,0,0,1,0},{0,0,0,1,1,0},{0,0,0,0,0,0}};System.out.println("Test 7: "+solution.shortestBridge(grid7));// 2}

关键点

  1. 两阶段

    • 第一阶段:识别并标记第一座岛
    • 第二阶段:多源BFS寻找第二座岛
  2. 多源BFS

    • 同时从第一座岛的所有位置开始搜索
    • 保证找到的路径是最短的
    • BFS的层数直接对应桥梁长度
  3. 标记

    • 使用2标记已访问的位置(第一座岛和已探索的水域)
    • 1表示第二座岛(目标)
    • 0表示未探索的水域
  4. 边界处理

    • 网格边界检查
    • 访问状态检查(避免重复访问)

常见问题

  1. 为什么使用多源BFS而不是单源BFS?
    • 多源BFS可以从第一座岛的所有边界同时扩展
    • 确保找到的路径是全局最短的
    • 单源BFS需要尝试每个起点,效率低下
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/9 16:07:32

没显卡怎么跑Python3.9?云端GPU 1小时1块,小白5分钟搞定

没显卡怎么跑Python3.9&#xff1f;云端GPU 1小时1块&#xff0c;小白5分钟搞定 你是不是也遇到过这种情况&#xff1a;周末想学点新东西&#xff0c;比如用 Python3.9 做个 AI 小项目&#xff0c;结果发现自己的 MacBook 跑不动&#xff1f;教程里动不动就说“需要 NVIDIA 显…

作者头像 李华
网站建设 2026/3/9 15:25:35

【字符编码】文本文件与二进制文件

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录一、核心定义与本质区别二、关键特征对比三、典型示例四、C/Qt 开发中的读写差异五、核心关联六、选型建议文本文件和二进制文件是计算机中两种核心的文件存储格式&a…

作者头像 李华
网站建设 2026/3/9 15:30:59

零基础学习Screen:简单命令快速上手指南

从“断连就崩”到稳如泰山&#xff1a;用screen拯救你的远程任务你有没有过这样的经历&#xff1f;深夜在公司服务器上跑一个内核编译&#xff0c;预计要两小时。你启动命令后安心地关掉笔记本回家——结果第二天打开电脑一看&#xff0c;SSH连接断了&#xff0c;进程也死了&am…

作者头像 李华
网站建设 2026/3/5 8:25:21

Live Avatar医疗咨询助手:医生形象数字人部署教程

Live Avatar医疗咨询助手&#xff1a;医生形象数字人部署教程 1. 章节名称 1.1 Live Avatar阿里联合高校开源的数字人模型 Live Avatar是由阿里巴巴与多所高校联合研发并开源的实时数字人生成模型&#xff0c;专注于高保真、低延迟的虚拟人物视频合成。该模型能够基于单张参…

作者头像 李华
网站建设 2026/3/9 2:26:22

YOLO11环境配置太难?这个镜像帮你解决

YOLO11环境配置太难&#xff1f;这个镜像帮你解决 在深度学习和计算机视觉领域&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;系列模型因其高效、准确的目标检测能力而广受欢迎。随着YOLO11的发布&#xff0c;开发者们迎来了更先进的架构与更高的性能表现。然而…

作者头像 李华