news 2026/3/26 16:27:45

算法题 最大人工岛

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法题 最大人工岛

827. 最大人工岛

问题描述

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

你可以将恰好一个海洋格子(即0)变为陆地(即1)。

返回执行此操作后,矩阵中最大岛屿面积。岛屿是由 4 个方向上相连的1形成的。

示例

输入:grid=[[1,0],[0,1]]输出:3解释:将 grid[0][1]变为1,可形成面积为3的岛屿。
输入:grid=[[1,1],[1,0]]输出:4解释:将 grid[1][0]变为1,整个矩阵变成一个面积为4的岛屿。
输入:grid=[[1,1],[1,1]]输出:4解释:矩阵中已经没有海洋格子,最大岛屿面积为4

算法思路

岛屿编号标记

  1. 遍历所有陆地,计算每个独立岛屿的面积

    • 使用 DFS/BFS 遍历每个未访问的陆地格子
    • 为每个岛屿分配唯一的编号(从 2 开始,避免与原始的 0、1 冲突)
    • 记录每个编号对应的岛屿面积
  2. 遍历所有海洋格子,模拟填海操作

    • 对于每个海洋格子 (0),检查其四个方向相邻的岛屿
    • 使用 Set 去重,避免重复计算同一个岛屿
    • 计算填海后可能形成的最大岛屿面积(1 + 所有相邻不同岛屿面积之和)
  3. 边界情况处理

    • 如果矩阵中全是陆地,直接返回总面积
    • 如果矩阵中全是海洋,返回 1(填一个格子)

代码实现

classSolution{// 方向数组:上下左右四个方向privatestaticfinalint[][]DIRECTIONS={{-1,0},{1,0},{0,-1},{0,1}};/** * 计算将一个海洋格子变为陆地后的最大岛屿面积 * * @param grid n x n 的二进制矩阵,0表示海洋,1表示陆地 * @return 最大岛屿面积 */publicintlargestIsland(int[][]grid){intn=grid.length;// 岛屿编号从2开始(避免与原始的0、1冲突)intislandId=2;// 记录每个岛屿编号对应的面积Map<Integer,Integer>islandArea=newHashMap<>();// 遍历所有格子,识别并标记所有岛屿for(inti=0;i<n;i++){for(intj=0;j<n;j++){// 如果当前格子是陆地(值为1),开始DFS计算岛屿面积if(grid[i][j]==1){intarea=dfs(grid,i,j,islandId);islandArea.put(islandId,area);islandId++;// 为下一个岛屿准备新的编号}}}// 初始化结果为当前最大岛屿面积(不进行填海操作的情况)intmaxArea=0;for(intarea:islandArea.values()){maxArea=Math.max(maxArea,area);}// 遍历所有海洋格子,模拟填海操作for(inti=0;i<n;i++){for(intj=0;j<n;j++){// 只处理海洋格子(值为0)if(grid[i][j]==0){// 使用Set记录相邻的不同岛屿编号,避免重复计算Set<Integer>neighborIslands=newHashSet<>();// 检查四个方向的相邻格子for(int[]dir:DIRECTIONS){intni=i+dir[0];intnj=j+dir[1];// 检查边界条件if(ni>=0&&ni<n&&nj>=0&&nj<n){// 如果相邻格子是陆地(编号>=2),加入Setif(grid[ni][nj]>=2){neighborIslands.add(grid[ni][nj]);}}}// 计算填海后的总面积:1(新填的格子)+ 所有相邻岛屿面积之和inttotalArea=1;for(intid:neighborIslands){totalArea+=islandArea.get(id);}maxArea=Math.max(maxArea,totalArea);}}}returnmaxArea;}/** * 深度优先搜索,计算岛屿面积并标记岛屿编号 * * @param grid 网格矩阵 * @param row 当前行坐标 * @param col 当前列坐标 * @param islandId 当前岛屿的编号 * @return 岛屿的面积 */privateintdfs(int[][]grid,introw,intcol,intislandId){intn=grid.length;// 边界检查:超出边界或不是陆地(原始值为1)if(row<0||row>=n||col<0||col>=n||grid[row][col]!=1){return0;}// 标记当前格子为当前岛屿编号grid[row][col]=islandId;// 初始化面积为1(当前格子)intarea=1;// 递归遍历四个方向的相邻格子for(int[]dir:DIRECTIONS){area+=dfs(grid,row+dir[0],col+dir[1],islandId);}returnarea;}}

算法分析

  • 时间复杂度:O(n²)
    • 每个格子最多被访问一次进行DFS,总时间复杂度 O(n²)
    • 遍历所有海洋格子,每个格子检查4个邻居,总时间复杂度 O(n²)
  • 空间复杂度:O(n²)
    • 岛屿面积映射表最多存储 O(n²) 个岛屿信息
    • DFS递归栈深度最坏情况下为 O(n²)
    • Set临时存储最多4个相邻岛屿编号,空间为 O(1)

算法过程

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

岛屿识别和标记

  1. 格子(0,0):值为1,开始DFS

    • 标记为岛屿2,面积=1
    • grid变为:[[2,0],[0,1]]
  2. 格子(1,1):值为1,开始DFS

    • 标记为岛屿3,面积=1
    • grid变为:[[2,0],[0,3]]
  3. 岛屿面积映射:{2: 1, 3: 1}

模拟填海

  1. 格子(0,1):海洋格子

    • 上:无,下:grid[1][1]=3,左:grid[0][0]=2,右:无
    • 相邻岛屿:{2, 3}
    • 总面积:1 + 1 + 1 = 3
  2. 格子(1,0):海洋格子

    • 上:grid[0][0]=2,下:无,左:无,右:grid[1][1]=3
    • 相邻岛屿:{2, 3}
    • 总面积:1 + 1 + 1 = 3

结果

  • 初始最大面积:1
  • 填海后最大面积:3
  • 返回结果:3

测试用例

publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:对角线岛屿int[][]grid1={{1,0},{0,1}};System.out.println("Test 1: "+solution.largestIsland(grid1));// 3// 测试用例2:三格陆地一格海洋int[][]grid2={{1,1},{1,0}};System.out.println("Test 2: "+solution.largestIsland(grid2));// 4// 测试用例3:全陆地int[][]grid3={{1,1},{1,1}};System.out.println("Test 3: "+solution.largestIsland(grid3));// 4// 测试用例4:全海洋int[][]grid4={{0,0},{0,0}};System.out.println("Test 4: "+solution.largestIsland(grid4));// 1// 测试用例5:复杂情况int[][]grid5={{1,0,1},{0,0,0},{1,0,1}};System.out.println("Test 5: "+solution.largestIsland(grid5));// 5// 测试用例6:单格int[][]grid6={{0}};System.out.println("Test 6: "+solution.largestIsland(grid6));// 1int[][]grid7={{1}};System.out.println("Test 7: "+solution.largestIsland(grid7));// 1// 测试用例8:大岛屿int[][]grid8={{0,0,0,0,0,0,0},{0,1,1,1,1,0,0},{0,1,0,0,1,0,0},{0,1,0,0,1,0,0},{0,1,1,1,1,0,0},{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}};System.out.println("Test 8: "+solution.largestIsland(grid8));// 17}

关键点

  1. 岛屿编号

    • 使用 ≥2 的编号标记不同岛屿,避免与原始数据冲突
    • 编号本身作为岛屿的唯一标识符
  2. 去重处理

    • 使用 Set 存储相邻岛屿编号,防止同一岛屿被重复计算
  3. 边界情况

    • 全陆地:直接返回总面积
    • 全海洋:返回1(填一个格子的最小面积)
    • 单格矩阵:根据值返回1

常见问题

  1. 为什么岛屿编号从2开始?
    原始矩阵中只有0(海洋)和1(陆地),使用≥2的编号可以清楚区分哪些是原始陆地,哪些是已标记的岛屿。

  2. 为什么需要Set去重?
    岛屿形状如"U"形,海洋格子可能被同一个岛屿从多个方向包围,如果不使用Set去重,会重复计算同一个岛屿的面积。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 7:51:50

MyListing – 目录与列表 WordPress 主题

MyListing 是一个目录和列表的WordPress主题&#xff0c;为你提供了前所未有的目录网站构建工具。 MyListing 页面是通过强大的前端页面构建器 Elementor 创建的。 所有50元素都是拖放式&#xff0c;易于使用和自定义。 完全不需要编程。 无论你是在创建企业、活动还是任何其他…

作者头像 李华
网站建设 2026/3/18 5:13:56

告别无脑 <div>:HTML 语义化标签入门

生活中的例子 01让屏幕阅读器&#xff08;盲人使用的工具&#xff09;能准确读出网页结构。生活中的例子 02让搜索引擎&#xff08;如 Google, 百度&#xff09;更好地理解你的网页内容&#xff0c;提升排名。生活中的例子 03让其他接手你代码的程序员一眼看懂网页布局&#xf…

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

go如何实现aop

Go 语言本身没有“类加载器”和“动态字节码增强”这一套基础设施&#xff0c;所以官方层面并不支持像 Java/Spring-AOP 那样的“全自动织入”。在 Go 里做 AOP&#xff0c;本质上是“手动织入”——把横切逻辑&#xff08;日志、权限、指标、重试等&#xff09;通过高阶函数、…

作者头像 李华
网站建设 2026/3/26 12:18:12

降低知网AIGC疑似度不用求人!1个降率网站+3条改写指令

2025年起&#xff0c;高校已明确要求毕业论文要检测AIGC率&#xff0c;AI率高于30%或40%就不能参加答辩&#xff0c;而部分学校、硕士论文更加严格&#xff0c;要求在20%以内。 这其中&#xff0c;大多数高校使用的AIGC检测系统是知网、万方、维普等主流查重系统&#xff0c;这…

作者头像 李华