目录

  • 零、题目描述
  • 一、为什么这道题值得一看?
  • 二、题目拆解:提取核心要素与约束
  • 三、算法实现:基于 DFS 的面积计算
    • 代码拆解
    • 时间复杂度
    • 空间复杂度
  • 四、与「岛屿数量」的代码对比(一目了然看差异)
  • 五、坑点总结
  • 六、举一反三
  • 七、总结

零、题目描述

题目链接:岛屿的最大面积

在这里插入图片描述

示例 1
在这里插入图片描述
输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。

示例 2:
输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0

一、为什么这道题值得一看?

如果你是第一次阅读我的题解文章,可能会好奇‘岛屿数量’与这道题的关联 —— 其实,「岛屿的最大面积」是「岛屿数量(LeetCode 200)」的经典进阶题,两者共享几乎相同的搜索框架,只是在目标上从‘统计岛屿个数’变成了‘计算最大面积’。

如果你想更系统地理解「洪水灌溉算法」的基础逻辑(比如 DFS 如何标记连通区域、如何处理边界条件),建议先看看昨天的文章(因为算法原理类似这篇文章讲解算法原理没有上一篇细致嘿嘿)力扣 200.岛屿数量。那里详细拆解了‘如何从 0 到 1 设计岛屿计数的代码’,读懂它再看今天的内容,会对‘搜索算法的复用与调整’有更清晰的认知~

如果你昨天跟着学了「岛屿数量」(LeetCode 200),那么这道题会是绝佳的“进阶练习”——它和前者共享 90% 的核心逻辑,但在细节上的差异能帮你更深刻理解「搜索算法的灵活性」。

从本质上看,两道题都是「连通区域问题」的变种:

  • 前者是计数问题(统计连通区域的数量);
  • 后者是计量问题(统计单个连通区域的最大规模)。

学会这道题,你能掌握:

  • 如何在搜索过程中累加数据(面积计算的核心);
  • 如何在多个结果中跟踪最大值
  • 进一步巩固「洪水灌溉(Flood Fill)」算法的通用框架。

二、题目拆解:提取核心要素与约束

先看原题:

给你一个由 1(陆地)和 0(水)组成的二进制矩阵 grid,请你计算网格中岛屿的最大面积。岛屿是由一些相邻的 1 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直的四个方向上相邻。你可以假设 grid 的四个边缘都被 0 包围着。岛屿的面积是岛上值为 1 的单元格的数目。

再结合所给的代码框架和提示:

class Solution {
public:int maxAreaOfIsland(vector<vector<int>>& grid) {}
};

核心要素提炼:

  • 题中给出的是由 vector 组成的二维数组 grid,元素类型是 int,取值只有 0(水)和 1(陆地);
  • 二维数组的长宽范围是 1 ≤ m, n ≤ 50m 为行数,n 为列数);
  • 核心任务是:找到所有由相邻 1 组成的岛屿,计算每个岛屿的面积(1 的数量),并返回其中的最大值;若没有岛屿,返回 0

关键点:

  1. 遍历网格:需用双重循环遍历每个单元格 (i,j),检查是否为未访问的陆地(grid[i][j] == 1)。
  2. 连通性判断:只有水平(左右)或垂直(上下)相邻的 1 属于同一岛屿,斜对角不算,因此搜索时仅需遍历四个方向。
  3. DFS/BFS 搜索:发现陆地时,需通过深度优先或广度优先遍历,找到该岛屿所有相连的 1,并计算面积。
  4. 标记已访问:为避免重复计算,需将已统计过的 1 标记为 0(原地修改,无需额外空间)。
  5. 面积计算与最大值跟踪
    • 对每个岛屿,通过递归或迭代累加 1 的数量(面积);
    • 用一个变量记录所有岛屿面积中的最大值,遍历完所有岛屿后返回该值。
  6. 边界处理:搜索相邻单元格时,需检查坐标是否在网格范围内(0 ≤ x < 行数0 ≤ y < 列数),防止越界。

与「岛屿数量」的共性(可直接复用的逻辑):

  1. 遍历网格:逐个检查每个单元格,发现未访问的陆地(1)时触发搜索;
  2. DFS 搜索:通过递归遍历当前陆地的上下左右,“淹没”(标记为 0)已访问的陆地,避免重复计算;
  3. 方向数组:用 dxdy 定义四个方向,简化代码(和昨天的 dx = [1,-1,0,0], dy = [0,0,1,-1] 完全相同)。

关键差异(今天要重点掌握的新逻辑):

  1. 从“计数”到“累加面积”

    • 昨天每触发一次 DFS,就给岛屿数量 +1
    • 今天每触发一次 DFS,需要统计这个岛屿包含多少个 1(即面积),用变量 n 实时累加。
  2. 跟踪最大面积

    • 每次 DFS 结束后(一个岛屿被完全“淹没”),将当前岛屿的面积 n 与全局最大面积 max_size 比较,更新最大值。

三、算法实现:基于 DFS 的面积计算

代码拆解

直接结合代码拆解核心逻辑(代码结构和昨天高度相似,重点看注释中标注的差异点):

class Solution {
public:int rows, cols;int max_size = 0;  // 记录全局最大面积(差异点1)int n = 0;         // 记录当前岛屿的面积(差异点2)int dx[4] = {1, -1, 0, 0};  // 方向数组(复用)int dy[4] = {0, 0, 1, -1};int maxAreaOfIsland(vector<vector<int>>& grid) {rows = grid.size();cols = grid[0].size();for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if (grid[i][j] == 1) {  // 发现新岛屿n = 0;              // 重置当前岛屿面积(差异点3)dfs(i, j, grid);    // 遍历整个岛屿,计算面积max_size = max(max_size, n);  // 更新最大面积(差异点4)}}}return max_size;}void dfs(int x, int y, vector<vector<int>>& grid) {grid[x][y] = 0;  // 淹没当前陆地(标记已访问,复用)n++;             // 当前岛屿面积+1(差异点5)// 遍历四个方向(复用)for (int i = 0; i < 4; i++) {int nx = x + dx[i];int ny = y + dy[i];// 检查边界+是否为未访问的陆地(复用)if (nx >= 0 && ny >= 0 && nx < rows && ny < cols && grid[nx][ny] == 1) {dfs(nx, ny, grid);  // 递归计算相邻陆地}}}
};

核心差异点深度解析:
上面的代码中,标为“差异点”的部分是今天的核心,我们逐个拆解:

  1. 变量 nmax_size 的作用

    • n:临时记录当前正在遍历的岛屿的面积,每次发现新岛屿时重置为 0;
    • max_size:全局变量,始终存储所有岛屿中最大的面积,每次一个岛屿遍历结束后更新。

    举例:如果网格中有 3 个岛屿,面积分别是 3、6、2,那么 max_size 会在遍历完第一个岛屿后变为 3,第二个后变为 6,第三个后保持 6。

  2. n 的累加时机
    进入 dfs 后,先将当前陆地标记为 0(避免重复访问),然后立即执行 n++——因为当前单元格是陆地(1),本身就贡献 1 个面积。

    反例:如果在递归结束后才 n++,会漏掉当前单元格的面积,导致结果偏小。

  3. max_size 的更新时机
    当一个岛屿的 DFS 完全结束后(即 dfs(i,j,grid) 执行完毕),n 已经记录了这个岛屿的完整面积,此时用 max(max_size, n) 比较并更新最大值。

分步运行示例(以示例 1 中最大岛屿为例)
为了更直观理解 n 和 max_size 的变化,我们以示例 1 中面积为 6 的岛屿为例,跟踪代码的关键执行步骤:

  1. 初始状态
    遍历网格时,首次遇到该岛屿的第一个陆地(坐标 (7,7),假设网格行索引从0开始),此时 grid[7][7] == 1

  2. 触发DFS前

    • 初始化 n = 0(准备统计当前岛屿面积);
    • 调用 dfs(7,7,grid)
  3. DFS递归过程

    • 第一层递归(7,7)
      grid[7][7] 改为 0(标记已访问),n 累加为 1
      检查四个方向,发现右侧 (7,8) 和上方 (6,7) 是陆地,优先递归 (7,8)

    • 第二层递归(7,8)
      grid[7][8] 改为 0n 累加为 2
      检查方向,发现上方 (6,8) 是陆地,递归 (6,8)

    • 第三层递归(6,8)
      grid[6][8] 改为 0n 累加为 3
      检查方向,发现左侧 (6,7) 是陆地,递归 (6,7)

    • 第四层递归(6,7)
      grid[6][7] 改为 0n 累加为 4
      检查方向,发现左侧 (6,6) 是水,下方 (7,7) 已访问,继续递归其他方向…

    • 后续递归:依次访问 (6,9)(7,9) 等相连陆地,n 逐步累加至 6

  4. DFS结束后
    该岛屿的所有陆地已被“淹没”(改为 0),n 的值为 6
    此时比较 nmax_size(初始为 0),更新 max_size = 6

通过这个过程可见:n 会随着递归深入实时累加,而 max_size 仅在整个岛屿遍历结束后更新,确保记录的是“完整岛屿”的最大面积。

时间复杂度

操作类型时间复杂度说明
网格整体遍历O(m×n)需通过双重循环遍历网格的每个单元格(共m×n个),检查是否为未访问的陆地
DFS递归处理O(m×n)每个陆地单元格(1)最多被访问一次(被标记为0后不再处理)
面积计算与比较O(1)每个岛屿的面积累加(n++)和最大值更新(max(max_size, n))均为常数操作
总计O(m×n)m为网格行数,n为列数,整体时间由遍历和递归的总操作数决定

补充说明:

  • 时间复杂度的核心瓶颈是“网格遍历”和“DFS递归”,两者的总操作次数均与网格大小(m×n)成正比,因此整体复杂度为O(m×n)。
  • 由于题目中网格规模较小(m, n ≤ 50),即使是最坏情况(全为陆地),总操作次数也仅为50×50=2500次,DFS递归栈深度不会导致栈溢出,效率完全可控。

空间复杂度

消耗场景空间复杂度说明
递归调用栈(DFS)O(m×n)最坏情况下(网格全为陆地,如 50×50 的全 1 网格),递归深度会达到网格总单元格数(m×n),此时栈空间消耗与网格规模成正比。
原地修改(无额外空间)O(1)算法通过直接修改原网格(将访问过的 1 改为 0)标记“已访问”,未使用额外的数据结构(如哈希表、布尔数组),因此仅消耗常数级空间。

补充说明:

  • 空间复杂度的瓶颈在于 DFS 的递归栈深度。由于题目中网格最大为 50×50,即使全为陆地,递归深度也仅为 2500,远低于大多数编程语言的栈空间上限(通常为 104~105),因此不会出现栈溢出问题。
  • 若改用 BFS 实现(用队列存储待访问坐标),空间复杂度同样为 O(m×n)(最坏情况下队列会存储所有陆地坐标),但避免了递归栈的限制,适合更大规模的网格场景。

四、与「岛屿数量」的代码对比(一目了然看差异)

为了更清晰地看出两道题的关系,我们用表格对比核心代码:

功能点岛屿数量(LeetCode 200)岛屿的最大面积(LeetCode 695)
核心目标统计岛屿的个数统计最大岛屿的面积
关键变量sum(岛屿计数器)n(当前岛屿面积)、max_size(最大面积)
触发搜索后操作sum++(每找到一个岛屿,计数器+1)n=0 → 执行 DFS → max_size = max(...)
DFS 内部操作仅标记陆地为 0,无额外计算标记陆地为 0 后,执行 n++(累加面积)

五、坑点总结

  1. 忘记重置 n
    如果在发现新岛屿时没有将 n 重置为 0,会导致多个岛屿的面积累加在一起(比如前一个岛屿面积 3,后一个会从 3 开始加),结果错误。

  2. max_size 初始化错误
    若初始化为 1 而非 0,当网格中没有岛屿(全为 0)时,会错误返回 1 而非 0

  3. 混淆 nmax_size 的作用
    不要在递归过程中更新 max_size,必须等一个岛屿完全遍历结束后再更新——否则可能把不完整的面积当作最大值。

六、举一反三

掌握了“计数”和“算面积”这两种变体,你可以尝试解决更复杂的连通区域问题:

  • LeetCode 130. 被围绕的区域:判断哪些 ‘O’ 被 ‘X’ 完全包围(从边界的 ‘O’ 出发标记所有连通区域,未标记的 ‘O’ 则被包围,需替换为 ‘X’)。
  • LeetCode 1020. 飞地的数量:计算无法从边界离开的陆地面积(在 DFS 基础上增加“是否触达边界”的判断);

这些问题的核心依然是「Flood Fill 搜索框架」,只是在“统计目标”上做了微调——学会透过问题看本质,算法学习会事半功倍。

七、总结

今天的题目是「岛屿数量」的完美进阶:它复用了相同的搜索逻辑,却通过一个小小的目标变化(从“计数”到“算面积”),让我们理解了如何在通用框架上进行灵活调整。

核心收获:

  • 复杂问题往往是简单问题的变体,掌握基础框架(如 DFS 遍历连通区域)是关键;
  • 解决“变体问题”时,重点关注目标的差异,并思考如何通过变量设计和流程调整来适配新目标。

如果对 DFS 的递归过程还不熟悉,建议回头再看昨天题解中关于“递归拆解”的部分——基础打牢了,再难的变体也能迎刃而解。

最后欢迎大家在评论区分享你的代码或思路,咱们一起交流探讨~ 🌟 要是有大佬有更精妙的思路或想法,恳请在评论区多多指点批评,我一定会虚心学习,并且第一时间回复交流哒!

在这里插入图片描述

这是封面原图~ 喜欢的话先点个赞鼓励一下呗~ 再顺手关注一波,后续更新不迷路,保证让你看得过瘾!😉

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89398.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89398.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/89398.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023 年 3 月青少年软编等考 C 语言八级真题解析

目录 T1. 最短路径问题 思路分析 T2. Freda 的越野跑 思路分析 T3. 社交网络 思路分析 T4. 旅行 思路分析 T1. 最短路径问题 题目链接:SOJ D1249 平面上有 n n n 个点( n ≤ 100 n\le 100 n≤100),每个点的坐标均在 − 10000 ∼ 10000 -10000\sim 10000 −10000∼10000…

UEditor富文本编辑器

UEditor配置部分在该项目中插入uediterUEditor是由百度FEX 前端团队开发并开源的一款功能强大、可定制性高的所见即所得&#xff08;WYSIWYG&#xff09;富文本编辑器。它的核心目标是帮助用户在网页上轻松编辑和发布格式丰富的内容&#xff08;如新闻、博客、论坛帖子、产品描…

Node.js 常用工具

Node.js 常用工具 引言 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者使用 JavaScript 编写服务器端应用程序。随着 Node.js 生态的日益完善,涌现出大量高效的工具,使得开发过程更加高效。本文将详细介绍一些在 Node.js 开发中常用的工具。 一、…

【unitrix】 6.7 基本结构体(types.rs)

一、源码 这是一个使用 Rust 类型系统实现类型级二进制数的方案&#xff0c;通过泛型和嵌套结构体在编译期表示数值。 //! 类型级二进制数表示方案 //! //! 使用嵌套泛型结构体表示二进制数&#xff0c;支持整数和实数表示。 //! //! ## 表示规则 //! - 整数部分: B<高位, 低…

基于Scikit-learn的机器学习建模与SHAP解释分析

基于Scikit-learn的机器学习建模与SHAP解释分析 1. 项目概述 本项目将使用Python的scikit-learn库对一个包含400条记录的数据集进行完整的机器学习建模流程,包括数据预处理、特征工程、模型训练和模型解释。我们将重点关注以下几个方面: 数据预处理:包括连续变量的标准化/…

QA:备份一般存储这块是怎么考虑?备份服务器如何选择?

1. 性能需求与架构设计 大数据平台的备份需满足高并发、加密传输、增量扫描、重复数据删除&#xff08;重删&#xff09;、数据压缩等复杂操作&#xff0c;对备份服务器的计算能力、存储吞吐及网络带宽提出极高要求。建议采用多节点集群架构&#xff0c;通过横向扩展提升备份效…

【东枫科技】用于汽车和工业传感器应用的高性能、集成式 24 GHz FMCW 雷达收发器芯片组

用于汽车和工业传感器应用的高性能、集成式 24 GHz FMCW 雷达收发器芯片组 ADF5904是一款高度集成的4通道、24 GHz接收机下变频器MMIC&#xff0c;具有卓越的低噪声性能、高线性度和低功耗组合。ADF5904集成式多通道接收机下变频器具有10 dB噪声系数性能&#xff0c;优于竞争型…

新版本flutter(3.32.7) android 端集成百度地图sdk

新版本flutter(3.32.7) android 端集成百度地图sdk 因为官方文档有很多地方没有说清楚,导致在适配过程中踩了很多坑,本文档基于已经实现集成的flutter安卓端应用编写。 官方文档地址:https://lbs.baidu.com/faq/api?title=flutter/loc/create-project/configure Flutt…

FreeRTOS—列表和列表项

文章目录一、列表与列表项1.1.列表与列表项的简介1.2.列表与列表项相关结构体1.2.1.列表结构体1.2.2.列表项结构体1.2.3.迷你列表项二、列表相关API函数2.1.列表相关API函数介绍2.1.1.vListInitalise( )初始化列表函数2.1.2.vListInitaliseItem( )初始化列表项函数2.1.3.vListI…

超详细 anji-captcha滑块验证uniapp微信小程序前端组件

由于步骤太多&#xff0c;字数太多&#xff0c;废话也太多&#xff0c;所以前后端分开讲了&#xff0c;后端文章请看&#xff1a; 超详细 anji-captcha滑块验证springbootuniapp微信小程序前后端组合https://blog.csdn.net/new_public/article/details/149116742 anji-captcha…

面向对象编程篇

文章目录一、思维导图二、详细内容第 6 章&#xff1a;面向对象编程基础6.1 面向对象编程的概念和优势6.2 类和对象的定义与创建6.3 类的属性和方法6.4 构造函数&#xff08;__init__&#xff09;和析构函数&#xff08;__del__&#xff09;6.5 封装、继承和多态的实现第 7 章&…

虚拟商品自动化实践:闲鱼订单防漏发与模板化管理的技术解析

最近阿灿发现了一款闲鱼虚拟商品卖家必备神器&#xff01;告别手动发货&#xff0c;订单自动处理&#xff0c;防错防漏&#xff0c;支持课程、激活码、电子书等多种商品&#xff0c;预设模板更省心。文末获取工具&#xff01;最厉害的是&#xff0c;你完全不用一直开着电脑。以…

【Zephyr开发实践系列】08_NVS文件系统调试记录

文章目录前言一、NVS原理介绍&#xff1a;二、BUG-NO1&#xff1a;将NVS运用在NAND-Flash类大容量存储设备2.1 情况描述&#xff1a;2.2 BUG复现&#xff1a;文件系统设备树构建测试应用编写&#xff08;导致错误部分&#xff09;&#xff1a;问题呈现&#xff1a;2.3 问题简述…

网络安全第二次作业

靶场闯关1~8 1. 在url后的name后输入payload ?name<script>alert(1)</script> 2. 尝试在框中输入上一关的payload,发现并没有通过&#xff0c;此时我们可以点开页面的源代码看看我们输入的值被送到什么地方去了 从图中可以看到&#xff0c;我们输入的值被送到i…

LangChain 源码剖析(七)RunnableBindingBase 深度剖析:给 Runnable“穿衣服“ 的装饰器架构

每一篇文章都短小精悍&#xff0c;不啰嗦。一、功能定位&#xff1a;Runnable 的 "增强包装器"RunnableBindingBase 是 LangChain 中实现装饰器模式的核心组件。它就像给原有 Runnable 套上一件 "功能外套"—— 不改变原有 Runnable 的核心逻辑&#xff0c…

为 Git branch 命令添加描述功能

写在最前面的使用方式 查看 所有分支的备注 git branch.notes创建分支并为分支添加备注 git co -b feat/oauth -m 第三方用户登录对分支描述的添加与清除 添加 git branch.note --add 清除 git branch.note --clear &#x1f4dd; 为 Git branch 命令添加描述功能 &#x…

LeetCode|Day18|20. 有效的括号|Python刷题笔记

LeetCode&#xff5c;Day18&#xff5c;20. 有效的括号&#xff5c;Python刷题笔记 &#x1f5d3;️ 本文属于【LeetCode 简单题百日计划】系列 &#x1f449; 点击查看系列总目录 >> &#x1f4cc; 题目简介 题号&#xff1a;20. 有效的括号 难度&#xff1a;简单 题目…

使⽤Pytorch构建⼀个神经⽹络

关于torch.nn:使⽤Pytorch来构建神经⽹络, 主要的⼯具都在torch.nn包中.nn依赖于autograd来定义模型, 并对其⾃动求导.构建神经⽹络的典型流程:定义⼀个拥有可学习参数的神经⽹络遍历训练数据集处理输⼊数据使其流经神经⽹络计算损失值将⽹络参数的梯度进⾏反向传播以⼀定的规则…

网络爬虫的详细知识点

基本介绍 什么是网络爬虫 网络爬虫&#xff08;Web Crawler&#xff09;是一种自动化程序&#xff0c;用于从互联网上抓取、解析和存储网页数据。其核心功能是模拟人类浏览行为&#xff0c;通过HTTP/HTTPS协议访问目标网站&#xff0c;提取文本、链接、图片或其他结构化信息&…

AndroidX中ComponentActivity与原生 Activity 的区别

一、AndroidX 与原生 Activity 的区别 1. 概念与背景 原生 Activity&#xff1a;指 Android 早期&#xff08;API 1 起&#xff09;就存在于 android.app 包下的 Activity 类&#xff08;如 android.app.Activity&#xff09;&#xff0c;是 Android 最初的 Activity 实现&…