【leetcode】200.岛屿数量

113 阅读3分钟

leetcode-200.png

题目描述:

给定一个由 '1'(陆地)和 '0'(水域)组成的二维网格,计算岛屿的数量。岛屿由水平或垂直方向上相邻的陆地组成,四个方向连接在一起的 '1' 视为一个岛屿。

这是图遍历中非常典型的一道题,需要在遍历过程中对访问过的位置进行标记,以避免重复统计。

DFS

思路:
当我们遇到一个 '1' 时,就以它为起点,使用递归的方式向上下左右扩散,将与其相连的所有 '1' 都标记为 '0'(淹没处理),这样可以避免后续重复访问。每次成功触发一次 DFS,说明遇到了一个新的岛屿,计数器加一即可。

注释都比较清楚就是,主要要注意的就是return的情况不能漏掉

var numIslands = function (grid) {
    let res = 0
    let row = grid.length, col = grid[0].length
    var dfs = function (i, j) {
        // 越界,直接return
        if (i < 0 || i >= row || j < 0 || j >= col) return
        // 遇到水 直接return
        if (grid[i][j] === '0') return
        // 符合条件的陆地,遍历到了之后,然后标记为水,避免下次遇到再计算
        grid[i][j] = '0'
        // 4个方向上都进行淹没的操作
        dfs(i - 1, j)
        dfs(i + 1, j)
        dfs(i, j - 1)
        dfs(i, j + 1)
    }
    for (let i = 0; i < row; ++i) {
        for (let j = 0; j < col; ++j) {
            if (grid[i][j] === '1') {
                // 进入一次dfs递归,把上下左右的陆地进行淹没
                dfs(i, j)
                // 四个方向上都淹没完了之后,岛屿数量++
                res++
            }
        }
    }
    return res
};

要点说明:

  • 每次递归遇到陆地 '1',就将其置为 '0'
  • 防止再次访问已处理的节点。
  • 所有与之连通的陆地都会被递归“淹没”。

BFS

思路:
使用队列进行逐层搜索。每次遇到 '1',就将其加入队列,然后将所有与之相邻的 '1' 也加入队列并标记为 '0',直到整片岛屿被遍历完毕。

var numIslands = function (grid) {
    let res = 0
    let row = grid.length
    let col = grid[0].length
    let direction = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    var bfs = function (i, j) {
        let queue = [[i, j]]
        while (queue.length) {
            let [x, y] = queue.shift()
            for (let [dx, dy] of direction) {
                let fx = dx + x
                let fy = dy + y
                if (fx >= 0 && fx < row && fy >= 0 && fy < col && grid[fx][fy] === '1') {
                    // 入队
                    queue.push([fx, fy])
                    // 重新标记
                    grid[fx][fy] = '0'
                }
            }
        }
    }
    for (let i = 0; i < row; ++i) {
        for (let j = 0; j < col; ++j) {
            if (grid[i][j] === '1') {
                res++
                grid[i][j] = '0'
                bfs(i, j)
            }
        }
    }
    return res
};

要点说明:

  • 使用队列来处理每一层的节点,直到当前岛屿的所有 '1' 都被“淹没”。
  • 每遇到一个 '1',就触发一次新的 BFS。

🧮 时间 & 空间复杂度分析

解法时间复杂度空间复杂度特点与适用场景
DFSO(m × n)O(m × n)(递归栈)实现简单,代码简洁,但递归深度大时易栈溢出
BFSO(m × n)O(m × n)(队列)稳定性更好,适合大数据量或对栈深度敏感的环境

m × n 是网格中元素总数。

🎯 总结建议

使用场景推荐方法
数据规模较小、对递归友好DFS
输入规模较大、追求稳定性BFS
后续扩展图路径、最短路径等BFS 更方便