# [200] 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [

["1","1","1","1","0"],

["1","1","0","1","0"],

["1","1","0","0","0"],

["0","0","0","0","0"]

]

输出:1

示例 2:

输入:grid = [

["1","1","0","0","0"],

["1","1","0","0","0"],

["0","0","1","0","0"],

["0","0","0","1","1"]

]

输出:3

这道题是经典的岛屿问题基础,所有的岛屿问题都可以归类为统一解决框架。即:判断当前节点是否被访问过,并分别对其连接节点进行深度遍历搜索,找到所有的联通点。

我们可以先建立一个 visited 二维数组,用于记录每一个节点是否被访问过。

接下来遍历 grid 的每一个节点,若当前节点是陆地,且之前未被访问过,则认为这是一块新岛屿, 结果 + 1。

之后使用 DFS 遍历其上下左右节点,访问到该岛屿上的所有节点,将这些位置的 visited 设为 true。

function numIslands(grid: string[][]): number {
  let res = 0;
  const height = grid.length;
  const width = grid[0].length;
  const visited: boolean[][] = Array(height)
    .fill(0)
    .map(x => Array(width).fill(false));

  for (let i = 0; i < height; i++) {
    for (let j = 0; j < width; j++) {
      if (grid[i][j] === '1' && !visited[i][j]) {
        res += 1;
        floodFill(i, j);
      }
    }
  }

  return res;

  function floodFill(i: number, j: number) {
    // 递归越界返回
    if (i < 0 || j < 0 || i >= height || j >= width) return;
    // 已遍历过,或者当前节点不是陆地时,返回
    if (visited[i][j] || grid[i][j] === '0') return;

    // 将当前点设置为已访问
    visited[i][j] = true;

    // 分别递归其上下左右节点
    floodFill(i - 1, j);
    floodFill(i + 1, j);
    floodFill(i, j - 1);
    floodFill(i, j + 1);
  }
}

当然,在本题中,其实可以不必要多维护一个 visited 数组。

由于 grid 中的每一个节点不会被二次使用到,我们可以直接改动原 grid 数组,将已访问过的陆地节点设置为 "0",将该陆地淹没,这样实现的效果完全相同。

function numIslands(grid: string[][]): number {
  let res = 0;
  const height = grid.length;
  const width = grid[0].length;
  for (let i = 0; i < height; i++) {
    for (let j = 0; j < width; j++) {
      if (grid[i][j] === '1') {
        res += 1;
        floodFill(i, j);
      }
    }
  }
  return res;

  function floodFill(i: number, j: number) {
    // 递归越界返回
    if (i < 0 || j < 0 || i >= height || j >= width) return;
    // 已遍历过,或者当前节点不是陆地时,返回
    if (grid[i][j] === '0') return;

    // 将当前点设置为已访问
    grid[i][j] = '0';

    // 分别递归其上下左右节点
    floodFill(i - 1, j);
    floodFill(i + 1, j);
    floodFill(i, j - 1);
    floodFill(i, j + 1);
  }
}