岛屿数量

这题本质上不是在数格子,而是在数连通块。每次找到一块没访问过的陆地,就把整块岛“淹掉”。

问题描述

LeetCode 200 - 岛屿数量

给定一个由’1’(陆地)和’0’(水)组成的二维网格,计算岛屿的数量。岛屿由水平或垂直方向相连的陆地组成,四周被水包围。

输入: grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出: 3

解题思路

  • DFS/BFS:遍历网格,遇到’1’就进行DFS/BFS
  • 标记访问:将访问过的’1’标记为’0’
  • 计数:每次DFS/BFS完成,岛屿数+1
  • 四个方向:上下左右四个方向扩展

为什么这样做

把网格想成图:

  • 每个 '1' 是一个可走节点。
  • 上下左右相邻的 '1' 之间连边。

那题目就在问:这个图里一共有多少个连通块。
所以只要扫到一个还没处理过的 '1',就立刻用 DFS 或 BFS 把整块连通区域全部标记掉,然后答案加一。

Go 代码

Go 实现

func numIslands(grid [][]byte) int {
    if len(grid) == 0 {
        return 0
    }
 
    rows, cols := len(grid), len(grid[0])
    count := 0
 
    var dfs func(int, int)
    dfs = func(r, c int) {
        if r < 0 || r >= rows || c < 0 || c >= cols || grid[r][c] == '0' {
            return
        }
 
        grid[r][c] = '0'
 
        dfs(r+1, c)
        dfs(r-1, c)
        dfs(r, c+1)
        dfs(r, c-1)
    }
 
    for r := 0; r < rows; r++ {
        for c := 0; c < cols; c++ {
            if grid[r][c] == '1' {
                count++
                dfs(r, c)
            }
        }
    }
 
    return count
}

易错点

岛屿数量的实现很短,但经常会在“访问标记”和“方向定义”上犯错。

  • 访问过的陆地一定要立刻标掉,否则会重复计数。
  • 题目默认只算上下左右,不算对角线。
  • 如果不想改原网格,就自己维护 visited。
  • 网格 DFS 最坏可能递归很深,特别大图时可以改 BFS。

复杂度分析

指标复杂度说明
时间复杂度O(M×N)遍历所有格子
空间复杂度O(M×N)递归栈(最坏情况)

相关主题


返回:图算法 | 算法学习导航