岛屿数量
回溯与搜索 · Flood Fill
数一数有几片陆地
给一张 0(水)/ 1(陆地)的方格地图,上下左右相连的陆地算作一个岛,问一共有几个岛。它和 迷宫寻路同样是网格搜索,但目标正好互补:迷宫是「从起点找一条路到终点」,岛屿是「扫描整张图、数出有几片连通的陆地」。
扫描 + Flood Fill
做法叫 Flood Fill(洪水填充),就是油漆桶工具的原理:逐格扫描整张网格,遇到一个还没访问过的陆地格,就说明发现了一个新岛——岛屿计数 +1,然后从这一格出发做 DFS,把与它四连通的整片陆地全部「淹掉」(标记为已访问),一片铺满后再继续扫描。已经淹过的陆地和水,扫描时直接跳过。
关键还是「标记已访问」:把数过的陆地沉成水(或另设 visited),才不会把同一个岛重复计数。它和迷宫是同一套网格 DFS 骨架,区别只在——迷宫找到终点就停,岛屿要把每一片都铺满、一直扫到底,最后计数就是答案。
下面是一张 4×4 网格(深色是水、浅色是未访问陆地)。点「下一步」逐步看:🔎 是当前扫描格,遇到新陆地就计数 +1 并 Flood Fill 把整片标绿;数完全图,绿色连通块共 3 片 —— 答案就是 3。右侧代码随每一步同步高亮。
🔎
扫描 (0,0):发现未访问陆地 → 第 1 个岛屿,从这里 Flood Fill
1function numIslands(grid: number[][]): number {
2 const rows = grid.length, cols = grid[0].length;
3 let count = 0;
4 const flood = (r: number, c: number): void => {
5 if (r < 0 || r >= rows || c < 0 || c >= cols) return;
6 if (grid[r][c] === 0) return; // 水 / 已访问
7 grid[r][c] = 0; // 标记为已访问(沉岛)
8 flood(r - 1, c); flood(r + 1, c);
9 flood(r, c - 1); flood(r, c + 1);
10 };
11 for (let r = 0; r < rows; r++) {
12 for (let c = 0; c < cols; c++) {
13 if (grid[r][c] === 1) { // 命中新陆地
14 count++;
15 flood(r, c);
16 }
17 }
18 }
19 return count;
20}
网格4×4(1=陆地/0=水)
当前格(0,0)
岛屿数1
已数陆地1
1 / 20
本页用 DFS 铺岛,也可以用 BFS(队列)一圈圈地淹,效果相同;把「数几片」换成「记录每片的大小」,就能求最大岛屿面积。Flood Fill 是连通分量在网格上的形态。
Flood Fill 在哪里用
图像处理:油漆桶填充、连通域标记、去除小噪点。
游戏:扫雷点开一片空格、消消乐找同色块、地图区域划分。
网格建模:岛屿 / 湖泊 / 势力范围计数,本质都是连通分量。
游戏:扫雷点开一片空格、消消乐找同色块、地图区域划分。
网格建模:岛屿 / 湖泊 / 势力范围计数,本质都是连通分量。
和 迷宫寻路两页对照着看——同一张网格、同一套 DFS,「找一条路」与「数所有连通块」是网格搜索最常见的一对目标。