最短的路

102 阅读2分钟

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

🎈算法并不一定都是很难的题目,也有很多只是一些代码技巧,多进行一些算法题目的练习,可以帮助我们开阔解题思路,提升我们的逻辑思维能力,也可以将一些算法思维结合到业务代码的编写思考中。简而言之,平时进行的算法习题练习带给我们的好处一定是不少的,所以让我们一起来养成算法练习的习惯。今天练习的题目是一道中等难度的题目 -> 最短的路

题目描述

给你一个大小为 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] 为 0 或 1
  • grid 中恰有两个岛

思路分析

首先我们要先理解一下题目的意思,题目会给我们一个二维数组,数组代表的是一片区域,其中数值为1的代表陆地,0代表水域,上下或左右相邻的所有1可以构成一座岛。

image.png

如上图,我们可以这样找出两座岛,现在题目的要求是要我们找到两座岛之间最短的水路,因为提示中说到grid 中恰有两个岛,所以我们可以先找到一座岛左右坐标点,再判断从这些坐标点中到另一座岛的最短路径,具体步骤写法如下:

  • 1、由一个点获取其完整岛的所有点

首先我们可以遍历这个数组,遇到第一个为1的位置时,我们可以从这个点向四周扩散,获取其所在完整岛的所有点,并给这个岛的所有点做上一个标记,这里我将第一个岛的所有点的值都改为2,用于和第二个岛作区分。

const getIsland = (x,y)=>{
    if(x >= grid.length || x < 0 || y < 0 || y >= grid[0].length) return;
    if(grid[x][y] == 0) return;
    grid[x][y] = 2;
    if(flag[x][y] !== Infinity) return;
    flag[x][y] = true;
    for(let i = 0; i < 4; i++){
        getIsland(x + dx[i],y + dy[i]);
    }
};
  • 2、计算从另一个岛走到当前岛的最短路径

继续遍历剩余的点,遇到值为1时,则说明当前点为第二个岛的点,我们可以从该点出发去往第一个岛,这里我们使用bfs来进行遍历寻路。遍历过的点我们可以先将其步数记录起来,后面再次遍历到该点的时候如果之前的步数比当前的步数要小,则说明我们不需要继续往后遍历了,这样可以剪去很多重复无效的遍历。

const calStep = (queue) => {
    while(queue.length){
        const q = queue.shift();
        if(grid[q[0]][q[1]] == 2){
            res = Math.min(res,q[2]);
            return;
        }
        if(flag[q[0]][q[1]] <= q[2]) continue;
        flag[q[0]][q[1]] = q[2];
        for(let i = 0; i < 4; i++){
            const x = q[0] + dx[i];
            const y = q[1] + dy[i];
            if(x >= grid.length || x < 0 || y < 0 || y >= grid[0].length) continue;
            if(flag[x][y] <= q[2]) continue;
            if(grid[x][y] == 1){
                calStep([[x,y,0]]);
            }else{
                queue.push([x,y,q[2] + 1]);
            }
        }
    }
};

完整AC代码如下:

AC代码

/**
 * @param {number[][]} grid
 * @return {number}
 */
 var shortestBridge = function(grid) {
    const dx = [1,0,-1,0],dy = [0,1,0,-1];
    let findFirstIsland = false;
    let res = Infinity;
    let flag = Array(grid.length).fill().map(() => Array(grid[0].length).fill(Infinity));
    const getIsland = (x,y)=>{
        if(x >= grid.length || x < 0 || y < 0 || y >= grid[0].length) return;
        if(grid[x][y] == 0) return;
        grid[x][y] = 2;
        if(flag[x][y] !== Infinity) return;
        flag[x][y] = true;
        for(let i = 0; i < 4; i++){
            getIsland(x + dx[i],y + dy[i]);
        }
    };
    const calStep = (queue) => {
        while(queue.length){
            const q = queue.shift();
            if(grid[q[0]][q[1]] == 2){
                res = Math.min(res,q[2]);
                return;
            }
            if(flag[q[0]][q[1]] <= q[2]) continue;
            flag[q[0]][q[1]] = q[2];
            for(let i = 0; i < 4; i++){
                const x = q[0] + dx[i];
                const y = q[1] + dy[i];
                if(x >= grid.length || x < 0 || y < 0 || y >= grid[0].length) continue;
                if(flag[x][y] <= q[2]) continue;
                if(grid[x][y] == 1){
                    calStep([[x,y,0]]);
                }else{
                    queue.push([x,y,q[2] + 1]);
                }
            }
        }
    };
    for(let i = 0; i < grid.length; i++){
        for(let j = 0; j < grid[i].length; j++){
            if(grid[i][j] == 1){
                if(!findFirstIsland){
                    findFirstIsland = true;
                    getIsland(i,j);
                    flag = Array(grid.length).fill().map(() => Array(grid[0].length).fill(Infinity));
                }else{
                    calStep([[i,j,0]]);
                    return res - 1;
                }
            }
        }
    }
    return res - 1;
};

说在后面

🎉这里是JYeontu,喜欢算法,GDCPC打过卡;热爱羽毛球,大运会打过酱油。毕业一年,两年前端开发经验,目前担任H5前端开发,算法业余爱好者,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。