news 2026/4/27 6:03:54

算法题 最短的桥

作者头像

张小明

前端开发工程师

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/4/23 7:35:33

MinerU适合初学者吗?零代码基础部署体验实操手册

MinerU适合初学者吗&#xff1f;零代码基础部署体验实操手册 1. 引言&#xff1a;MinerU为何值得关注&#xff1f; 1.1 初学者的AI模型使用困境 对于没有编程或深度学习背景的用户而言&#xff0c;部署和使用视觉多模态模型往往面临诸多挑战&#xff1a;复杂的环境依赖、庞大…

作者头像 李华
网站建设 2026/4/24 0:44:03

Z-Image-Turbo实战案例:8步生成照片级图像的完整部署步骤详解

Z-Image-Turbo实战案例&#xff1a;8步生成照片级图像的完整部署步骤详解 1. 引言 1.1 业务场景描述 随着AI生成内容&#xff08;AIGC&#xff09;技术的快速发展&#xff0c;文生图模型在创意设计、广告制作、游戏开发等领域展现出巨大潜力。然而&#xff0c;许多开源模型存…

作者头像 李华
网站建设 2026/4/25 11:50:44

从0开始学YOLO11:简单易懂的目标检测教程

从0开始学YOLO11&#xff1a;简单易懂的目标检测教程 1. 引言&#xff1a;为什么选择YOLO11&#xff1f; 目标检测是计算机视觉中的核心任务之一&#xff0c;广泛应用于自动驾驶、安防监控、工业质检等领域。近年来&#xff0c;YOLO&#xff08;You Only Look Once&#xff0…

作者头像 李华
网站建设 2026/4/26 6:41:27

Z-Image-Turbo镜像使用痛点:系统盘保护注意事项实战提醒

Z-Image-Turbo镜像使用痛点&#xff1a;系统盘保护注意事项实战提醒 1. 背景与核心价值 随着文生图大模型在创意设计、内容生成等领域的广泛应用&#xff0c;用户对“开箱即用”高性能推理环境的需求日益增长。Z-Image-Turbo作为阿里达摩院&#xff08;ModelScope&#xff09…

作者头像 李华
网站建设 2026/4/21 14:08:48

TurboDiffusion日志分析:常见错误代码排查与修复指南

TurboDiffusion日志分析&#xff1a;常见错误代码排查与修复指南 1. 引言 1.1 背景与问题提出 随着AI视频生成技术的快速发展&#xff0c;TurboDiffusion作为由清华大学、生数科技和加州大学伯克利分校联合推出的高效视频生成加速框架&#xff0c;凭借其在单张RTX 5090显卡上…

作者头像 李华
网站建设 2026/4/23 15:57:56

MinerU-1.2B教程:文档水印去除技巧详解

MinerU-1.2B教程&#xff1a;文档水印去除技巧详解 1. 引言 1.1 业务场景描述 在日常办公与学术研究中&#xff0c;PDF文档、扫描件和截图常包含版权水印、背景图案或机构标识。这些附加元素虽然具有法律或品牌保护意义&#xff0c;但在进行OCR文字提取、内容摘要生成或数据…

作者头像 李华