leetcode
leetcode 451 ~ 500
迷宫

迷宫

难度:

标签:

题目描述

代码结果

运行时间: 42 ms, 内存: 17.2 MB


/*
题目思路:
我们可以使用Java Stream API进行DFS的实现。这里的思路是创建一个流来处理迷宫中的每一个点,
使用递归方法来进行DFS搜索。
*/
 
import java.util.stream.Stream;
import java.util.function.IntPredicate;
 
public class MazeStream {
    private static final int[] DIRS = {-1, 0, 1, 0, -1}; // 用于上下左右移动的方向数组
    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        if (maze == null || maze.length == 0 || maze[0].length == 0) return false;
        boolean[][] visited = new boolean[maze.length][maze[0].length];
        return dfs(maze, start, destination, visited);
    }
    private boolean dfs(int[][] maze, int[] start, int[] destination, boolean[][] visited) {
        if (visited[start[0]][start[1]]) return false;
        if (start[0] == destination[0] && start[1] == destination[1]) return true;
        visited[start[0]][start[1]] = true;
        return Stream.of(0, 1, 2, 3).anyMatch(dir -> {
            int x = start[0];
            int y = start[1];
            while (x >= 0 && x < maze.length && y >= 0 && y < maze[0].length && maze[x][y] == 0) {
                x += DIRS[dir];
                y += DIRS[dir + 1];
            }
            x -= DIRS[dir];
            y -= DIRS[dir + 1];
            return dfs(maze, new int[]{x, y}, destination, visited);
        });
    }
}
 

解释

方法:

这个题解使用深度优先搜索(DFS)来判断从起点是否能到达终点。具体来说,从起点开始,沿着四个方向(上下左右)一直滚动,直到撞到墙或者到达边界。每个位置只访问一次,如果滚动到终点则返回 true,否则继续尝试其他方向。如果所有方向都尝试过仍无法到达终点,则返回 false。

时间复杂度:

O(mn * max(m, n))

空间复杂度:

O(mn)

代码细节讲解

🦆
在DFS中,为什么选择一直滚动直到撞墙或出界,而不是每次只移动一步?这种滚动方式对解题有什么特殊的优势吗?
在这个迷宫问题中,选择一直滚动到撞墙或出界而不是每次只移动一步的主要原因是,这种滚动方式可以更有效地模拟球在迷宫中的实际移动。实际上,球在没有障碍物的情况下会持续滚动直到撞到墙壁。这种方法减少了必须考虑的节点数量,因为它跳过了在直线路径上的多个中间步骤,从而提高了搜索效率。此外,这也确保了算法更快地跨越空旷区域,减少了递归深度,从而在一定程度上减少了栈溢出的风险。
🦆
在DFS递归中,当到达一个新位置且未被访问时,如果递归调用返回true,为何可以立即断定整个DFS返回true?这里是否有潜在的回溯机制被省略?
在DFS递归中,如果递归调用返回true,意味着从当前位置到终点已经找到了一条有效路径。因此,可以立即断定整个DFS返回true,并结束所有进一步的搜索。这里并没有省略回溯机制,实际上这是回溯的一部分。当递归调用找到一个成功的路径时,它会逐层返回true,递归地传播这个成功的结果。如果没有找到有效路径,递归调用会返回false,然后尝试其他可能的路径。这确保了即使部分路径失败,搜索也能继续进行,直到找到有效路径或确认没有路径存在。
🦆
该算法是否考虑了所有可能的边界情况,例如迷宫中的所有位置都是墙壁,或起点和终点位置相同的情况?
该算法考虑了起点和终点位置相同的情况,因为它首先检查起点是否即为终点,如果是,则立即返回true。然而,对于迷宫中的所有位置都是墙壁这种情况,根据题解的代码实现,如果起点是墙,则函数将不会进行任何有效的DFS调用,因此会返回false。但如果没有明确检查起点是否为墙,这可能需要在实际应用中额外验证确保输入数据的有效性。
🦆
在实际的DFS实现中,每次滚动停止后,你检查的是`new_i + dx`和`new_j + dy`,这一步是否可能导致对边界的错误判断?
在题解中的DFS实现里,每次滚动停止前的检查确保了我们不会越界。在`while`循环中,条件`0 <= new_i + dx < m`和`0 <= new_j + dy < n`以及`maze[new_i + dx][new_j + dy] == 0`被用来保证不会滚动到墙上或出界。因此,这样的检查是正确的并且防止了对边界的错误判断,它确保了只有在滚动到有效的空白位置时才停止。

相关问题

迷宫 III

迷宫 III

迷宫 II

迷宫 II