leetcode
leetcode 451 ~ 500
迷宫 II

迷宫 II

难度:

标签:

题目描述

代码结果

运行时间: 59 ms, 内存: 16.6 MB


/*
 * 思路:
 * 1. 虽然Java Stream API主要用于处理集合数据,但我们仍然可以使用它来简化部分代码,例如初始化距离矩阵。
 * 2. 使用BFS算法来找到最短路径,其他逻辑与传统方法类似。
 */
 
import java.util.*;
import java.util.stream.IntStream;
 
public class MazeIIStream {
    private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
 
    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        int m = maze.length, n = maze[0].length;
        int[][] distance = IntStream.range(0, m).mapToObj(i -> IntStream.generate(() -> Integer.MAX_VALUE).limit(n).toArray()).toArray(int[][]::new);
        distance[start[0]][start[1]] = 0;
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(start);
 
        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            for (int[] dir : DIRECTIONS) {
                int x = curr[0], y = curr[1], dist = distance[x][y];
                while (isValid(x + dir[0], y + dir[1], maze)) {
                    x += dir[0];
                    y += dir[1];
                    dist++;
                }
                if (dist < distance[x][y]) {
                    distance[x][y] = dist;
                    queue.offer(new int[]{x, y});
                }
            }
        }
 
        int result = distance[destination[0]][destination[1]];
        return result == Integer.MAX_VALUE ? -1 : result;
    }
 
    private boolean isValid(int x, int y, int[][] maze) {
        return x >= 0 && x < maze.length && y >= 0 && y < maze[0].length && maze[x][y] == 0;
    }
}
 

解释

方法:

这道题使用 Dijkstra 算法求解最短路径。主要思路是利用优先队列(小根堆)来存储节点,每次从队列中取出距离最小的节点进行扩展,直到找到终点或者所有可达节点都已访问过。在迷宫中,从一个位置可以往四个方向滚动,每个方向滚动到obstacles或边界时停止,计算每一段连续滚动的距离,更新相邻节点的最短距离。

时间复杂度:

O(mn * (m+n))

空间复杂度:

O(mn)

代码细节讲解

🦆
为什么选择使用Dijkstra算法而不是BFS或DFS来解决这个迷宫问题?
Dijkstra算法适用于处理带权重的图中的最短路径问题,其中每个转移的代价可以不同。在迷宫问题中,每次移动可以跨越多个空白单元格,直到遇到边界或障碍,因此每次移动的成本(距离)是变化的。相比之下,BFS仅适用于每步成本相同的情况,而DFS则主要用于遍历或搜索,不专注于找到最短路径。因此,使用Dijkstra算法可以更精确地处理不同移动成本,从而找到真正的最短路径。
🦆
优先队列中的元素是如何确定优先级的,是仅仅基于距离吗?
是的,在这个迷宫问题的Dijkstra算法实现中,优先队列中的元素优先级是基于每个节点到起点的累计距离。这是因为Dijkstra算法的核心是每次都从已探索的节点中选择一个具有最小累计距离的节点进行扩展,以保证算法的正确性和效率。
🦆
代码中提到'如果当前距离大于已记录的最短距离,跳过',这样做的具体原因是什么?为什么当前距离会大于已记录的最短距离?
这种情况发生是因为同一个节点可能通过不同的路径被多次添加到优先队列中。当从队列中取出一个节点时,如果它的距离大于已记录的最短距离,这意味着我们已经找到了一个更优的路径到达这个节点。继续处理这个较大距离的节点将是无效的,因为它不会导致任何更短的路径。跳过这样的节点可以避免不必要的计算,提高算法效率。
🦆
在不断向外扩展时,如何处理边界条件以防止数组越界?
在向外扩展时,代码通过检查每个新坐标是否在迷宫的边界内来处理边界条件。即在每次尝试移动到新位置之前,都会检查新的行坐标和列坐标是否在迷宫的有效范围(0到m-1行和0到n-1列)。如果坐标超出这个范围,就不会继续在该方向移动,从而避免了数组越界的问题。

相关问题

迷宫

迷宫

迷宫 III

迷宫 III