搜索题目:二进制矩阵中的最短路径

文章目录

题目

标题和出处

标题:二进制矩阵中的最短路径

出处:1091. 二进制矩阵中的最短路径

难度

5 级

题目描述

要求

给定一个 n × n \texttt{n} \times \texttt{n} n×n 的二进制矩阵 grid \texttt{grid} grid,返回矩阵中最短畅通路径 的长度。如果不存在畅通路径,返回 -1 \texttt{-1} -1。

二进制矩阵中的畅通路径 是一条从左上角 单元格(即 (0, 0) \texttt{(0, 0)} (0, 0))到右下角 单元格(即 (n − 1, n − 1) \texttt{(n} - \texttt{1, n} - \texttt{1)} (n−1, n−1))的路径,该路径同时满足下述要求:

  • 路径途经的所有单元格的值都是 0 \texttt{0} 0。
  • 路径中所有相邻的单元格应当在 8 \texttt{8} 8 个方向之一上连通(即相邻两个单元格彼此不同且共享一条边或者一个角)。

畅通路径的长度是该路径途经的单元格总数。

示例

示例 1:

输入: grid = [[0,1],[1,0]] \texttt{grid = [[0,1],[1,0]]} grid = [[0,1],[1,0]]

输出: 2 \texttt{2} 2

示例 2:

输入: grid = [[0,0,0],[1,1,0],[1,1,0]] \texttt{grid = [[0,0,0],[1,1,0],[1,1,0]]} grid = [[0,0,0],[1,1,0],[1,1,0]]

输出: 4 \texttt{4} 4

示例 3:

输入: grid = [[1,0,0],[1,1,0],[1,1,0]] \texttt{grid = [[1,0,0],[1,1,0],[1,1,0]]} grid = [[1,0,0],[1,1,0],[1,1,0]]

输出: -1 \texttt{-1} -1

数据范围

  • n = grid.length \texttt{n} = \texttt{grid.length} n=grid.length
  • n = grid[i].length \texttt{n} = \texttt{grid[i].length} n=grid[i].length
  • 1 ≤ n ≤ 100 \texttt{1} \le \texttt{n} \le \texttt{100} 1≤n≤100
  • grid[i][j] \texttt{grid[i][j]} grid[i][j] 为 0 \texttt{0} 0 或 1 \texttt{1} 1

解法

思路和算法

边长为 n n n 的矩阵中的任意一条畅通路径都满足起点位于矩阵的左上角 ( 0 , 0 ) (0, 0) (0,0),终点位于矩阵的右下角 ( n − 1 , n − 1 ) (n - 1, n - 1) (n−1,n−1)。如果矩阵中存在畅通路径,则畅通路径的起点 ( 0 , 0 ) (0, 0) (0,0) 和终点 ( n − 1 , n − 1 ) (n - 1, n - 1) (n−1,n−1) 都必须是 0 0 0。如果 grid [ 0 ] [ 0 ] = 1 \textit{grid}[0][0] = 1 grid[0][0]=1 或 grid [ n − 1 ] [ n − 1 ] = 1 \textit{grid}[n - 1][n - 1] = 1 grid[n−1][n−1]=1,则矩阵中一定不存在畅通路径,返回 − 1 -1 −1。以下只考虑 grid [ 0 ] [ 0 ] = grid [ n − 1 ] [ n − 1 ] = 0 \textit{grid}[0][0] = \textit{grid}[n - 1][n - 1] = 0 grid[0][0]=grid[n−1][n−1]=0 的情况。

如果一条畅通路径中存在重复访问的单元格,则可以将同一个单元格的两次不同访问之间的部分的路径去掉,得到更短的畅通路径,因此最短畅通路径中一定不存在重复访问的单元格。

由于广度优先搜索的遍历顺序是和起始点的距离递增的顺序,因此可以使用广度优先搜索计算最短畅通路径的长度,做法是从左上角单元格出发执行广度优先搜索,搜索过程中维护一个与矩阵相同大小的二维数组,用于记录矩阵中的每个单元格和起点之间的最短路径长度,该二维数组称为距离数组。根据畅通路径长度的计算规则,左上角单元格对应的最短路径长度是 1 1 1。

遍历结束之后,根据右下角单元格是否已访问,返回结果。

  • 如果右下角单元格已访问,则右下角单元格对应的距离数组中的元素为最短畅通路径的长度,返回该长度。

  • 如果右下角单元格未访问,则不存在从左上角单元格到右下角单元格的畅通路径,返回 − 1 -1 −1。

实现方面有以下两点说明。

  1. 对于每个单元格需要向八个方向遍历,可以创建方向数组实现八个方向的遍历。

  2. 广度优先搜索需要记录每个单元格是否被访问过,这道题由于需要计算每个单元格和起始点之间的最短路径长度,因此可以根据距离数组中的元素判断每个单元格是否被访问过。具体做法是,将矩阵中的左上角单元格对应的距离数组中的元素初始化为 1 1 1,将矩阵中的其余单元格对应的距离数组中的元素初始化为无穷大,则距离数组中的值为无穷大的元素表示该单元格未访问。

代码

java 复制代码
class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {1, 1}, {-1, 1}, {1, -1}};
    static final int INFINITY = Integer.MAX_VALUE / 2;

    public int shortestPathBinaryMatrix(int[][] grid) {
        int n = grid.length;
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) {
            return -1;
        }
        int[][] distances = new int[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(distances[i], INFINITY);
        }
        distances[0][0] = 1;
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(new int[]{0, 0});
        while (!queue.isEmpty() && distances[n - 1][n - 1] == INFINITY) {
            int[] cell = queue.poll();
            int row = cell[0], col = cell[1];
            for (int[] dir : dirs) {
                int newRow = row + dir[0], newCol = col + dir[1];
                if (newRow >= 0 && newRow < n && newCol >= 0 && newCol < n && grid[newRow][newCol] == 0 && distances[newRow][newCol] == INFINITY) {
                    distances[newRow][newCol] = distances[row][col] + 1;
                    queue.offer(new int[]{newRow, newCol});
                }
            }
        }
        return distances[n - 1][n - 1] != INFINITY ? distances[n - 1][n - 1] : -1;
    }
}

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 是矩阵 grid \textit{grid} grid 的边长。广度优先搜索最多需要访问每个单元格一次。

  • 空间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 是矩阵 grid \textit{grid} grid 的边长。距离数组和队列需要 O ( n 2 ) O(n^2) O(n2) 的空间。

相关推荐
伟大的车尔尼2 天前
搜索题目:被围绕的区域
并查集·深度优先搜索·广度优先搜索
伟大的车尔尼8 天前
搜索题目:地图分析
动态规划·广度优先搜索
伟大的车尔尼9 天前
搜索题目:腐烂的橘子
广度优先搜索
伟大的车尔尼10 天前
搜索题目:01 矩阵
动态规划·广度优先搜索
伟大的车尔尼15 天前
搜索题目:图像渲染
并查集·深度优先搜索·广度优先搜索
伟大的车尔尼17 天前
搜索题目:甲板上的战舰
并查集·深度优先搜索·广度优先搜索
伟大的车尔尼23 天前
广度优先搜索和深度优先搜索的概念
数据结构·算法·并查集·深度优先搜索·广度优先搜索
老鼠只爱大米3 个月前
LeetCode经典算法面试题 #104:二叉树的最大深度(深度优先搜索、广度优先搜索等多种实现方案详细解析)
算法·leetcode·二叉树·dfs·bfs·深度优先搜索·广度优先搜索
EXtreme354 个月前
【数据结构】二叉树进阶:层序遍历不仅是按层打印,更是形态判定的利器!
c语言·数据结构·二叉树·bfs·广度优先搜索·算法思维·面试必考