📌  相关文章
📜  门| Sudo GATE 2020 Mock III(2019 年 1 月 24 日)|第 64 题(1)

📅  最后修改于: 2023-12-03 14:58:33.679000             🧑  作者: Mango

题目描述

给定一个由 '0' 和 '1' 组成的矩阵,其中 '0' 表示通道,'1' 表示墙壁,找到从矩阵中某一门到达另一扇门的最短路线。门用 'M' 标识。

每一步可以往上、下、左、右移动。您可以假设矩阵的四个边框均为墙。

如果找不到这样一条路径,则返回 -1。

例如,给定以下矩阵:

[0, 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
['M', 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 'M', 0, 0],
[0, 0, 0, 0, 1],
]

其中,两个门为 'M',一个矩阵可视为:

从左下角的门(下图右下角)到右上角的门(下图左上角)的最短路径是 10 步。

算法

广度优先算法(BFS)

广度优先算法是一种遍历图或树的算法,从根节点开始, 沿着宽度遍历节点, 如果这个节点没有被遍历过, 那么将它的所有邻居节点加入遍历的队列中,并标记为已遍历。

在本题中,使用广度优先算法可以寻找一条从起点到终点的最短路径。

实现
  • 创建一个 visited 数组,标记节点是否被访问过;
  • 创建一个队列,用于宽度优先搜索;
  • 从起始节点开始,循环所有邻居节点;
  • 如果邻居节点没有被访问过,将其加入队列中并标记为已访问;
  • 如果邻居节点是终点节点,返回此时的步数。
复杂度分析
  • 时间复杂度:$O(m*n)$,m 和 n 分别代表矩阵的行数和列数。
  • 空间复杂度:$O(m*n)$,需要一个同样大小的 visited 数组和队列。

代码实现

def find_path(maze):
    """
    :type maze: List[List[int]]
    :rtype: int
    """
    if not maze or not maze[0]:
        return -1

    directions = [(-1, 0), (0, -1), (1, 0), (0, 1)]
    m, n = len(maze), len(maze[0])

    def bfs(queue):
        steps = 0
        while queue:
            steps += 1
            for _ in range(len(queue)):
                x, y = queue.pop(0)
                for dx, dy in directions:
                    nx, ny = x + dx, y + dy
                    if 0 <= nx < m and 0 <= ny < n and maze[nx][ny] != 1 and not visited[nx][ny]:
                        if maze[nx][ny] == "M":
                            return steps
                        else:
                            queue.append((nx, ny))
                            visited[nx][ny] = True
        return -1

    maze = [[1] * (n + 2)] + [[1] + r + [1] for r in maze] + [[1] * (n + 2)]
    visited = [[False] * (n + 2) for _ in range(m + 2)]
    start, end = None, None
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if maze[i][j] == "M":
                if not start:
                    start = (i, j)
                else:
                    end = (i, j)
    return bfs([start]) if start and end else -1