The Maze II

update Sep 5,2017 23:58

LeetCodearrow-up-right

There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up, down, left or right, but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction.

Given the ball's start position, the destination and the maze, find the shortest distance for the ball to stop at the destination. The distance is defined by the number of empty spaces traveled by the ball from the start position (excluded) to the destination (included). If the ball cannot stop at the destination, return -1.

The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the borders of the maze are all walls. The start and destination coordinates are represented by row and column indexes.

Example 1

Input 1: a maze represented by a 2D array

         0 0 1 0 0
         0 0 0 0 0
         0 0 0 1 0
         1 1 0 1 1
         0 0 0 0 0

Input 2: start coordinate (rowStart, colStart) = (0, 4)
Input 3: destination coordinate (rowDest, colDest) = (4, 4)

Output: 12
Explanation: One shortest way is : left -> down -> left -> down -> right -> down -> right.
                      The total distance is 1 + 1 + 3 + 1 + 2 + 2 + 2 = 12.

Example 2

Note:

  • There is only one ball and one destination in the maze.

  • Both the ball and the destination exist on an empty space, and they will not be at the same position initially.

  • The given maze does not contain border (like the red rectangle in the example pictures), but you could assume the border of the maze are all walls.

  • The maze contains at least 2 empty spaces, and both the width and height of the maze won't exceed 100.

Basic Idea:

思路 1:DFS or BFS 暴力更新最短路径

这种方法维持一个distance[][] table,从start开始暴力搜索,每次撞墙停止后,更新到达点的distance,再向周围继续搜索。

Time Complexity: 因为搜索覆盖所有从start出发的路径可能,时间复杂度为 O(m*n*max(m,n))。 因为共有 m*n 个节点,每个节点的搜索可以在不撞墙的情况下搜索 max(m,n) 个格子;

思路 2:Dijkstra Algorithm

利用 Dijkstra 单源最短路径的算法,维持一个 distance[][] table,从start开始,使用一个 priority queue,每次取当前距离 start 最近的点作为起始点 bfs。撞墙停止之后更新 distance。根据 Dijkstra 算法的定义,每次 poll 出队的节点都是当前已经完成的节点,所以只要遇到 destination 被poll出,就可以结束搜索。

Time Complexity: O(m * n * log(mn)),因为至多有 (mn)个节点和 (mn)条边。

JavaCode:

上面的实现除了使用 distance[][] 之外还使用了一个 visited[][] table 来标记每个完成的点,但是事实上我们无需这么做。判断一个节点v是否完成,只需要判断 distance[v] 是否小于当前出队节点所记录的距离,如果小于,那么 v 已经完成。

下面的 python code 就使用了这样的简化思路:

update 2018-05-25 14:03:204

C++ Solution

和之前相比进行了一些简化,由于Dijkstra算法可以保证每次出队的vertex都是当前queue中距离start最近的点,所以当destination出队的时候,就可以直接返回其对应的weight。(这里每个点的weight实际是指其到start的距离)

update 06/08/2021

三年之后的更新,感觉在很多细节的处理上都较以前更加成熟

Last updated