# [1905] 统计子岛屿

给你两个 m x n 的二进制矩阵 grid1 和 grid2 ,它们只包含 0 (表示水域)和 1 (表示陆地)。一个 岛屿 是由 四个方向 (水平或者竖直)上相邻的 1 组成的区域。任何矩阵以外的区域都视为水域。

如果 grid2 的一个岛屿,被 grid1 的一个岛屿 完全 包含,也就是说 grid2 中该岛屿的每一个格子都被 grid1 中同一个岛屿完全包含,那么我们称 grid2 中的这个岛屿为 子岛屿 。

请你返回 grid2 中 子岛屿 的 数目 。

示例 1:

输入:grid1 = [[1,1,1,0,0],[0,1,1,1,1],[0,0,0,0,0],[1,0,0,0,0],[1,1,0,1,1]],

grid2 = [[1,1,1,0,0],[0,0,1,1,1],[0,1,0,0,0],[1,0,1,1,0],[0,1,0,1,0]]

输出:3

解释:如上图所示,左边为 grid1 ,右边为 grid2 。

grid2 中标红的 1 区域是子岛屿,总共有 3 个子岛屿。

示例 2:

输入:grid1 = [[1,0,1,0,1],[1,1,1,1,1],[0,0,0,0,0],[1,1,1,1,1],[1,0,1,0,1]],

grid2 = [[0,0,0,0,0],[1,1,1,1,1],[0,1,0,1,0],[0,1,0,1,0],[1,0,0,0,1]]

输出:2

解释:如上图所示,左边为 grid1 ,右边为 grid2 。

grid2 中标红的 1 区域是子岛屿,总共有 2 个子岛屿。

提示:

m == grid1.length == grid2.length

n == grid1[i].length == grid2[i].length

1 <= m, n <= 500

grid1[i][j] 和 grid2[i][j] 都要么是 0 要么是 1 。

这也是一道岛屿淹没题型。解题方法就不多加赘述了,详见 DFS 专题

这里主要说说如何判断岛屿 2 中的岛屿是否为岛屿 1 的子岛屿。

我们可以反向思维,先将 grid1 与 grid2 每个节点一一比对,当发现某个节点在 grid2 是岛屿而在 grid1 不是,直接淹没 grid2 的这个岛屿。

这样一来,grid2 剩余还未被淹没的岛屿即一定为 grid1 的子岛屿。

因此调用同一个算法两遍,仅在第二遍执行时记录岛屿数量,即可完成此题。

function countSubIslands(grid1: number[][], grid2: number[][]): number {
  let res = 0;

  const direction = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1]
  ];
  const rowLen = grid1.length;
  const colLen = grid1[0].length;

  // 先将 grid1 与 grid2 每个节点一一比对
  for (let i = 0; i < rowLen; i++) {
    for (let j = 0; j < colLen; j++) {
      // 发现某个节点在 grid2 是岛屿而在 grid1 不是,淹没 grid2 的这个岛屿
      if (grid2[i][j] === 1 && grid1[i][j] !== 1) {
        backtrack(i, j);
      }
    }
  }

  // grid2 剩余没被淹没的岛屿则一定是子岛屿了
  for (let i = 0; i < rowLen; i++) {
    for (let j = 0; j < colLen; j++) {
      if (grid2[i][j] === 1) {
        backtrack(i, j);
        res += 1;
      }
    }
  }

  return res;

  function backtrack(row: number, col: number) {
    if (row < 0 || row >= rowLen || col < 0 || col >= colLen) return;
    if (grid2[row][col] !== 1) return;

    grid2[row][col] = 2;

    for (const [i, j] of direction) {
      backtrack(row + i, col + j);
    }
  }
}