题目

你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。

我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。

如果我们的地图上只有陆地或者海洋,请返回 -1。

示例

输入:[[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释:
海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。

分析

参考链接:参考链接点这里

花了好长时间去理解题意,距离最近的陆地区域的最远距离,究竟是最远距离还是最近距离,后来看了链接中大佬画的 GIF 瞬间明白了,这道题或许换个模型更容易理解。

我脑补的模型:

  • 背景:
    • 病毒在封闭人群中的传播(可能是最近瘟疫公司玩多了的缘故 orz);
  • 假设:
    • 将陆地看成是感染人员,每个感染人员 每天 都会感染周围的人,然后 第二天新感染的人员又会感染周围的人,问:你以上帝视角,站在人群中什么位置,才是最晚被感染的人(人类之光格陵兰)。
  • 思路:
    • 第一天,算出被 0 号病人感染的人,剩下没感染的还有多少人
    • 第二天,算出被 第一天感染的人 感染的人,剩下没感染多少人
    • ……
    • 第 N 天,已经没有被感染的人了
    • 得到 N

题解

/**
 * @param {number[][]} grid
 * @return {number}
 */
var maxDistance = function (grid) {
    let land = []; // 陆地源数组
    let level = 0; // 返回层级
    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[i].length; j++) {
            if (grid[i][j] === 1) {
                land.push([i, j]);
            }
        }
    }
    let ocean = grid.length * grid.length - land.length; // 海洋的格数
    // 全是海洋或者陆地,返回 -1
    if (land.length === 0 || ocean === 0) {
        return -1;
    }
    while (ocean > 0) {
        level++;
        const temp = [];
        for (let i = 0; i < land.length; i++) {
            const [x, y] = [land[i][0], land[i][1]];
            // 判断 上下左右 相邻的点是否有海洋
            for (let j = 0; j < 4; j++) {
                // 边界条件校验
                if (
                    x + dx[j] < 0 ||
                    y + dy[j] < 0 ||
                    x + dx[j] > grid.length - 1 ||
                    y + dy[j] > grid[0].length - 1
                ) {
                    continue;
                }
                // 如果发现是海洋,则标记 2(这里其实只要是非 0,其他数都可以,只为了跟未知海洋作区分),防止被重复计算
                if (grid[x + dx[j]][y + dy[j]] === 0) {
                    grid[x + dx[j]][y + dy[j]] = 2;
                    temp.push([x + dx[j], y + dy[j]]);
                    // 每发现一个新海洋,剩下的海洋格数就减少 1
                    ocean--;
                }
            }
        }
        land = temp; // 一轮扩散结束后,新扩散将代替源陆地存入 land,开始新的一轮扩散
    }
    return level;
};
const dx = [1, -1, 0, 0];
const dy = [0, 0, 1, -1];