跳到主要内容

BM57. 岛屿数量

题目描述​

给一个 01 矩阵,1 代表陆地,0 代表海洋,上下左右相邻的 1 属于同一个岛。 判断岛屿个数。(存储的 01 数据其实是字符 '0'、'1'。)

输入格式​

  • grid:字符型二维数组,只含 0 与 1。

输出格式​

返回 int 型,岛屿的数量。

示例​

示例 1​

输入:

grid = [[1,1,0,0,0],[0,1,0,1,1],[0,0,0,1,1],[0,0,0,0,0],[0,0,1,1,1]]

输出:

3

说明: 左上角一片、右侧一片、下方一片,共 3 座岛。

示例 2​

输入:

grid = [[0]]

输出:

0

说明: 全是海洋,没有岛。

示例 3​

输入:

grid = [[1,1],[1,1]]

输出:

1

说明: 四格相连,是一整座岛。


解题思路​

第一步:理解问题本质​

「岛屿」= 四联通的 1 组成的连通块。求连通块的数量, 就是经典的「网格洪水填充 / Flood Fill」问题。

第二步:遍历 + DFS 淹没​

扫描每个格子:

  • 遇到一个还没访问过的陆地,就说明发现了一座新岛(数量 +1);
  • 立刻从它出发做一次 DFS/BFS,把所有相连的陆地都标记成「已访问」, 相当于把这座岛「淹没」,之后就不会重复计数。

「发现一座岛,就淹没一整片」,是这个模板的核心。

第三步:两种实现​

  • DFS:递归或栈。递归写法最短,但大网格可能爆栈, 用显式栈(迭代 DFS)更稳。
  • BFS:队列,天然不会爆栈,适合连通块特别大的情况。

两者复杂度一样,都是 O(rows × cols)。

一个细节:题面说「存储的 01 数据其实是字符」,但示例又写成整数。 稳妥起见,判断陆地时同时接受 '1' 和 1,并用独立的 seen 数组标记, 不去修改入参。


完整代码实现​

算法可视化 · 逐帧回放这道题的代码306 帧 · 录制输入 [[1,1,0,0,0],[0,1,0,1,1],[0,0,0,1,1],[0,0,0,0,0],[0,0,1,1,1]]
from typing import List


class Solution:
def solve(self, grid: List[List[str]]) -> int:
"""统计 01 矩阵里的四联通岛屿数量"""
if not grid or not grid[0]:
return 0
rows, cols = len(grid), len(grid[0])
seen = [[False] * cols for _ in range(rows)]
dirs = ((1, 0), (-1, 0), (0, 1), (0, -1))
count = 0

def is_land(i: int, j: int) -> bool:
# 兼容字符 '1' 与整数 1 两种入参
return not seen[i][j] and grid[i][j] in ('1', 1)

for i in range(rows):
for j in range(cols):
if is_land(i, j):
count += 1 # 发现新岛
seen[i][j] = True
stack = [(i, j)]
while stack: # 淹没整座岛
x, y = stack.pop()
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if 0 <= nx < rows and 0 <= ny < cols and is_land(nx, ny):
seen[nx][ny] = True
stack.append((nx, ny))
return count

示例推演​

以示例 1 的矩阵为例:

1 1 0 0 0
0 1 0 1 1
0 0 0 1 1
0 0 0 0 0
0 0 1 1 1
扫描到的第一个未访问陆地淹没的格子岛屿数
(1,1)(1,1)(1,2)(2,2)1
(2,4)(2,4)(2,5)(3,4)(3,5)2
(5,3)(5,3)(5,4)(5,5)(4,3)(4,4)3

扫描结束,答案为 3。


复杂度分析​

解法时间复杂度空间复杂度说明
DFS(迭代栈)O(rows*cols)O(rows*cols)推荐
BFSO(rows*cols)O(rows*cols)大块连通时更稳

易错点总结​

1. 忘记标记已访问​

不标记会让同一座岛被反复计数,或在 DFS 里无限打转。

2. 入参类型不统一​

题面说是字符,示例写成整数。用 in ('1', 1) 兼容两者, 不要硬写 == '1'。

3. 只考虑四联通​

只算上下左右,不算对角线。八个方向会把「斜挨着的两座岛」误当成一座。


扩展思考​

  • 若要求「最大岛屿面积」,把发现岛时的计数改成统计淹没的格子数并取最大。
  • 「封闭岛屿」(不接触边界的岛)只需在淹没时判断是否碰到边界。
  • 同类问题还可以用并查集合并相邻陆地来求解。

相关题目​

自测​

加载评论中...