最短的桥

119 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

934. 最短的桥 - 力扣(LeetCode)

给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。

是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid恰好存在两座岛

你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛

返回必须翻转的 0 的最小数目。

示例 1:

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

示例 2:

输入: grid = [[0,1,0],[0,0,0],[0,0,1]]
输出: 2

示例 3:

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

提示:

  • n == grid.length == grid[i].length
  • 2 <= n <= 100
  • grid[i][j]01
  • grid 中恰有两个岛

思路

本题可以使用广度优先搜索解题。先找到其中的一个岛,遍历出所有相邻的水域(0),然后再遍历这些相邻的水域,找到他们相邻的水域,只到找到另一个岛(1),遍历次数就是最短路径。为了防止重复遍历,我们可以把遍历过的岛和水域标记为-1

解题

/**
 * @param {number[][]} grid
 * @return {number}
 */
var shortestBridge = function (grid) {
  let n = grid.length;
  let sides = [];
  const steps = [
    [1, 0],
    [-1, 0],
    [0, 1],
    [0, -1],
  ];
  const getIsland = (i, j, grid) => {
    if (i >= 0 && i < n && j >= 0 && j < n) {
      const val = grid[i][j];
      grid[i][j] = -1;
      if (val === 1) {
        for (let k = 0; k < 4; k++) {
          getIsland(i + steps[k][0], j + steps[k][1], grid) && island;
        }
      } else if (val === 0) {
        sides.push([i, j]);
      }
    }
  };
  let state = false;
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] === 1) {
        getIsland(i, j, grid);
        state = true;
        break;
      }
    }
    if (state) {
      break;
    }
  }
  let res = 1;
  while (true) {
    let arr = [];
    for (let i = 0; i < sides.length; i++) {
      for (let k = 0; k < 4; k++) {
        const r = sides[i][0] + steps[k][0];
        const c = sides[i][1] + steps[k][1];

        if (r >= 0 && r < n && c >= 0 && c < n) {
          if (grid[r][c] === 0) {
            arr.push([r, c]);
            grid[r][c] = -1;
          } else if (grid[r][c] === 1) {
            return res;
          }
        }
      }
    }
    res++;
    sides = arr;
  }
};