
一、核心思路
- 遍历二维网格的每一个单元格;
- 当遇到未访问的陆地
'1',岛屿数量 + 1; - 调用 DFS,把该位置上下左右 4 方向连通 的所有陆地全部置为
'0'(原地标记已访问,不需要额外 visited 数组); - DFS 终止条件:坐标越界,或者当前格子是水域
'0',直接返回; - 四个方向依次递归,遍历整片连通陆地;
- 网格全部遍历完毕,返回岛屿总数。
连通规则:仅上下左右,斜对角不算连通。
二、完整 Java 代码
scss
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
int m = grid.length;//行数
if(m == 0) return 0; //处理空网格
int n = grid[0].length;//列数
//1.遍历每一个格子
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == '1') {
count++;
dfs(grid, i, j);
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j) {
//递归中止条件:越界,或者当前水域
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') {
return;
}
//标记当前陆地已经被淹没
grid[i][j] = '0';
dfs(grid, i - 1, j);//上
dfs(grid, i + 1, j);//下
dfs(grid, i, j - 1);//左
dfs(grid, i, j + 1);//右
}
}
三、实例演示(示例 1)
原始网格:
| 行 \ 列 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 0 | '1' | '1' | '1' | '1' | '0' |
| 1 | '1' | '1' | '1' | '1' | '0' |
| 2 | '1' | '1' | '0' | '1' | '0' |
| 3 | '1' | '1' | '0' | '0' | '0' |
| 4 | '0' | '0' | '0' | '0' | '0' |
| 步骤 | 操作 | count | 网格状态说明 |
|---|---|---|---|
| 1 | i=0,j=0,检测到'1',count++,调用 DFS |
count=1 | 开始淹没连通陆地 |
| 2 | DFS 递归,上下左右遍历,所有连通的'1'全部修改为'0' |
count=1 | 整片陆地全部标记为水 |
| 3 | 继续循环遍历剩下单元格,全部是'0',不会触发新岛屿 |
count=1 | 无新增岛屿 |
| 4 | 遍历结束,返回结果 | 1 | 输出答案 1 |
四、复杂度分析
- 时间复杂度:(O(m * n)),m 行 n 列,每个格子最多访问 1 次
- 空间复杂度:(O(m * n)),最坏情况网格全是陆地,递归栈深度达到(m* n)
五、易错点总结
- 判断条件:陆地是
'1',水是'0',不要写反; - 字符判断必须带单引号,
'0',不能直接写数字 0; - 边界判断:
i >= grid.length,不能写成i > grid.length,否则数组下标越界; - 连通只有上下左右,斜向相邻不算同一个岛屿。
六、个人感悟
岛屿数量是网格 DFS 的模板题。核心思想就是:遇到一块新陆地,就一次性把所有相连陆地全部 "淹没",统计一共能找到多少次新陆地。除 DFS 递归版本外,还可以用 BFS 队列迭代实现。