岛屿数量问题
字数 1456 2025-12-10 06:37:35
岛屿数量问题
题目描述
给定一个由 '1'(陆地)和 '0'(水)组成的二维网格地图,计算网格中岛屿的数量。一个岛屿被水包围,并且通过水平方向或垂直方向上相邻的陆地连接形成。你可以假设网格的四个边均被水包围。
示例
输入:
grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出: 3
详细解题步骤
-
理解问题核心
岛屿是由相邻的 '1' 组成的连通区域,相邻指上下左右四个方向。目标是统计这样的连通区域个数。这本质上是在二维矩阵中寻找连通分量的数量,可以用深度优先搜索(DFS)、广度优先搜索(BFS)或并查集(Union-Find)解决。 -
DFS 解法思路
- 遍历整个网格,对每个格子进行检查。
- 如果当前格子是 '1',说明发现了一个新岛屿,于是:
- 将岛屿数量加一。
- 对这个格子进行 DFS,把与它相连的所有陆地(即上下左右方向上的 '1')都标记为已访问,避免重复计数。
- 如何标记已访问?可以直接将访问过的 '1' 改成 '0' 或一个特殊字符(如 '#'),这样后续遍历就不会再把它当成新岛屿的起点了。
-
DFS 递归函数的细节
- 函数定义:
dfs(grid, i, j),其中(i, j)是当前格子的坐标。 - 递归终止条件:
- 坐标越界(超出网格范围)。
- 当前格子是 '0'(水)或已访问过的格子。
- 递归过程:
- 将当前格子标记为已访问(如
grid[i][j] = '0')。 - 对当前格子的四个方向(上、下、左、右)分别递归调用 DFS。
- 将当前格子标记为已访问(如
- 函数定义:
-
方向数组的使用
为了代码简洁,可以定义一个方向数组:
directions = [(0,1), (0,-1), (1,0), (-1,0)]
分别对应右、左、下、上四个方向。在递归中,通过循环遍历这四个方向,生成新坐标(ni, nj),然后递归调用。 -
完整算法步骤
- 初始化岛屿数量
count = 0。 - 遍历网格的每个格子
(i, j):- 如果
grid[i][j] == '1':count++- 调用
dfs(grid, i, j)将整个岛屿标记掉。
- 如果
- 返回
count。
- 初始化岛屿数量
-
复杂度分析
- 时间复杂度:O(M×N),其中 M 是行数,N 是列数。每个格子最多被访问一次。
- 空间复杂度:O(M×N)(最坏情况下递归栈的深度,例如整个网格都是陆地时)。
-
BFS 解法简介
也可以用队列实现 BFS 来替代 DFS 的递归过程:- 当遇到 '1' 时,将其入队,然后不断取出队首元素,将其四个方向中为 '1' 的邻居入队并标记,直到队列为空。
- BFS 的空间复杂度在最坏情况下也是 O(M×N)(队列可能存储较多节点)。
-
并查集解法思路
- 将每个 '1' 的格子视为一个独立的集合。
- 遍历网格,对每个 '1' 的格子,检查其右侧和下侧的格子(避免重复检查),如果也是 '1',则将它们合并到同一个集合。
- 最终,岛屿数量 = 集合的总数 - 水的格子所在的集合数(通常水的格子单独视为一个集合,或不计入)。实际实现时,可以只统计 '1' 的格子在并查集中的根节点个数。
-
总结
岛屿数量问题是二维矩阵中连通分量计数的经典问题,DFS/BFS 是直观解法,并查集在需要动态合并的场景中更高效。关键在于理解如何通过搜索或合并来标记整个连通区域,避免重复计数。