LeetCode LCR 105. 岛屿的最大面积
题目描述


题意分析
网格中的
1表示陆地,只有上下左右相邻的陆地才属于同一座岛。岛屿面积就是它包含的陆地格数,要求返回最大面积,没有陆地时返回0。把陆地格看成节点、四方向相邻关系看成边,岛屿就是连通分量。对每个尚未访问的分量搜索一次,统计格数并取最大值即可。
解法:DFS 淹没并统计岛面积
核心思路
[!blue]
dfs(i,j)返回从当前位置出发,本次搜索新访问的陆地格数。调用前保证坐标合法;若格子是0,它是海水或已经统计过的陆地,直接贡献0。遇到
1时,先把当前格改为0,并把局部面积初始化为1,再递归搜索四个合法邻居,累加它们返回的新增面积。必须先标记再递归,否则相邻陆地会互相走回,重复统计甚至无法终止。四方向搜索会到达同一座岛的所有陆地,却无法跨过海水到其他岛。每个陆地格在首次进入时就被标记,其他分支再次遇到它只返回
0,因此每个格子恰好计入一次,递归总和就是该岛面积。外层遍历全部格子,取每次
dfs返回值的最大值。一座岛第一次被访问时已经全部标记,后续从其中其他位置发起的调用都返回0。答案从零开始,所以全海水时自然返回零。代码直接修改grid作为访问标记,搜索结束后已访问陆地会变成0。
解题步骤
- 保存网格行列数,将最大面积初始化为
0。- 枚举每个格子,调用
dfs并用返回面积更新最大值。- 递归遇到
0返回零;遇到陆地则先置零,计入当前格贡献的一。- 用方向数组相邻两项表示上下左右偏移,先检查邻居坐标,再递归累加面积。
- 返回本次面积;外层扫描结束后返回最大面积。单行、单列也由相同的边界判断处理。
代码实现
class Solution {
private int m;
private int n;
private int[][] grid;
public int maxAreaOfIsland(int[][] grid) {
m = grid.length;
n = grid[0].length;
this.grid = grid;
int answer = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
answer = Math.max(answer, dfs(i, j));
}
}
return answer;
}
private int dfs(int i, int j) {
// 海水或已被淹没的陆地,贡献 0 个格子。
if (grid[i][j] == 0) {
return 0;
}
int answer = 1;
// 必须在递归之前淹没自己,否则邻居会走回来造成无限递归。
grid[i][j] = 0;
int[] dirs = {
-1,
0,
1,
0,
-1
};
for (int k = 0; k < 4; ++k) {
int x = i + dirs[k];
int y = j + dirs[k + 1];
if (x >= 0 && x < m && y >= 0 && y < n) {
answer += dfs(x, y);
}
}
return answer;
}
}
func maxAreaOfIsland(grid [][]int) (answer int) {
m, n := len(grid), len(grid[0])
dirs := [5]int{
-1,
0,
1,
0,
-1,
}
var dfs func(i, j int) int
dfs = func(i, j int) int {
// 海水或已被淹没的陆地,贡献 0 个格子。
if grid[i][j] == 0 {
return 0
}
answer := 1
// 必须在递归之前淹没自己,否则邻居会走回来造成无限递归。
grid[i][j] = 0
for k := 0; k < 4; k++ {
x, y := i+dirs[k], j+dirs[k+1]
if x >= 0 && x < m && y >= 0 && y < n {
answer += dfs(x, y)
}
}
return answer
}
for i := range grid {
for j := range grid[i] {
answer = max(answer, dfs(i, j))
}
}
return
}
复杂度分析
- 时间复杂度:$O(mn)$。外层扫描全部格子,每块陆地只展开一次,每次只检查四个邻居;海水或已访问位置立即返回。
- 空间复杂度:$O(mn)$。最坏情况下,一条搜索路径经过所有陆地,递归深度可达到网格总格数;方向信息只占每层常数空间。
关键点总结
[!green]
- 一座岛对应一个四连通分量,面积统计完成后再与全局最大值比较。
- 进入陆地后立即标记,使递归分支的新增计数互不重复。
- 当前格自己贡献一,邻居返回的是额外找到的陆地数。
- 用原网格记录访问状态会修改输入,但不需要额外访问矩阵。
易错点总结
[!yellow]
- 递归邻居后才标记当前格,会让相邻陆地反复走回。
- 把斜对角也当作邻居,会合并本来不同的岛屿。
- 只累加邻居却忘记当前格的一,会把面积算小。
- 把所有岛的面积持续累加到一个全局计数,得到的是总陆地数而不是最大单岛面积。
- 当前实现只在调用邻居前检查坐标,不能把越界位置直接传给
dfs。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 200. 岛屿数量 | 中等 | 同样寻找四连通分量,原题只累计岛屿个数,本题累计每块面积并取最大。 |
| 827. 最大人工岛 | 困难 | 在岛屿面积基础上允许翻转一个0,需要合并相邻不同分量的面积并避免重复计入。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!