LeetCode——迷宫 i-ii

Q:由空地和墙组成的迷宫中有一个球。球可以向上下左右四个方向滚动,但在遇到墙壁前不会停止滚动。当球停下时,可以选择下一个方向。
给定球的起始位置,目的地和迷宫,判断球能否在目的地停下。
迷宫由一个0和1的二维数组表示。 1表示墙壁,0表示空地。你可以假定迷宫的边缘都是墙壁。起始位置和目的地的坐标通过行号和列号给出。

示例 1:
输入 1: 迷宫由以下二维数组表示

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

输入 2: 起始位置坐标 (rowStart, colStart) = (0, 4)
输入 3: 目的地坐标 (rowDest, colDest) = (4, 4)
输出: true
解析: 一个可能的路径是 : 左 -> 下 -> 左 -> 下 -> 右 -> 下 -> 右。

示例 2:
输入 1: 迷宫由以下二维数组表示

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

输入 2: 起始位置坐标 (rowStart, colStart) = (0, 4)
输入 3: 目的地坐标 (rowDest, colDest) = (3, 2)
输出: false
解析: 没有能够使球停在目的地的路径。

A:DFS和BFS双解。
DFS:我们从起始位置开始,每次选择一条路线进行搜索,并用一个二维布尔数组 visited 表示是否曾经到达过位置 (i, j) ,若在某一次搜索到位置 (i, j) 时,visited[i, j] = true,那么我们可以进行回溯,不必继续搜索下去。

    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        boolean[][] visited = new boolean[maze.length][maze[0].length];
        for (int i = 0; i < maze.length; i++) {
            Arrays.fill(visited[i], false);
        }
        return dfs(maze, start[0], start[1], destination, visited);
    }

    private boolean dfs(int[][] maze, int x, int y, int[] destination, boolean[][] visited) {
        //走过,说明该位置所有情况都考虑了一遍但找不到出路
        if (visited[x][y])
            return false;
        if (x == destination[0] && y == destination[1])
            return true;
        visited[x][y] = true;
        int r = y + 1, l = y - 1, u = x - 1, d = x + 1;
        int m = maze.length, n = maze[0].length;
        //右走到头后所有结果都走一遍
        while (r < n && maze[x][r] == 0)
            r++;
        if (dfs(maze, x, r - 1, destination, visited))
            return true;
        //左走到头后所有结果都走一遍
        while (l >= 0 && maze[x][l] == 0)
            l--;
        if (dfs(maze, x, l + 1, destination, visited))
            return true;
        //上走到头后所有结果都走一遍
        while (u >= 0 && maze[u][y] == 0)
            u--;
        if (dfs(maze, u + 1, y, destination, visited))
            return true;
        //下走到头后所有结果都走一遍
        while (d < m && maze[d][y] == 0)
            d++;
        if (dfs(maze, d - 1, y, destination, visited))
            return true;
        //上下左右都没法找到出路
        return false;
    }

BFS:同样用一个visited把走过的记下来

    private int[] idx = {-1, 0, 1, 0, -1};

    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        int m = maze.length, n = maze[0].length;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < maze.length; i++) {
            Arrays.fill(visited[i], false);
        }
        Queue<int[]> q = new LinkedList<>();
        q.add(start);
        while (!q.isEmpty()) {
            int[] curr = q.poll();
            int x = curr[0];
            int y = curr[1];
            visited[x][y] = true;
            if (x == destination[0] && y == destination[1])
                return true;
            for (int k = 0; k < 4; k++) {
                int nx = x + idx[k];
                int ny = y + idx[k+1];
                while (nx >= 0 && ny >= 0 && nx < maze.length && ny < maze[0].length && maze[nx][ny] == 0) {
                    nx = nx + idx[k];
                    ny = ny + idx[k+1];
                }
                nx = nx - idx[k];
                ny = ny - idx[k+1];
                if(visited[nx][ny])
                    continue;
                q.add(new int[]{nx, ny});
            }
        }
        return false;
    }

Q:由空地和墙组成的迷宫中有一个球。球可以向上下左右四个方向滚动,但在遇到墙壁前不会停止滚动。当球停下时,可以选择下一个方向。
给定球的起始位置,目的地和迷宫,找出让球停在目的地的最短距离。距离的定义是球从起始位置(不包括)到目的地(包括)经过的空地个数。如果球无法停在目的地,返回 -1。
迷宫由一个0和1的二维数组表示。 1表示墙壁,0表示空地。你可以假定迷宫的边缘都是墙壁。起始位置和目的地的坐标通过行号和列号给出。

示例 1:
输入 1: 迷宫由以下二维数组表示

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

输入 2: 起始位置坐标 (rowStart, colStart) = (0, 4)
输入 3: 目的地坐标 (rowDest, colDest) = (4, 4)
输出: 12
解析: 一条最短路径 : left -> down -> left -> down -> right -> down -> right。
总距离为 1 + 1 + 3 + 1 + 2 + 2 + 2 = 12。

示例 2:
输入 1: 迷宫由以下二维数组表示

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

输入 2: 起始位置坐标 (rowStart, colStart) = (0, 4)
输入 3: 目的地坐标 (rowDest, colDest) = (3, 2)
输出: -1
解析: 没有能够使球停在目的地的路径。

A:同样DFS和BFS双解。
DFS:可以使用深度优先搜索对整颗搜索树进行遍历。我们从起始位置开始,每次选择一条路线进行搜索,并用计数器 count 记录当前的步数。为了防止重复搜索,我们需要使用一个二维数组 distance 记录从起始位置到 (i, j) 的最小步数 distance[i, j],若在某一次搜索到位置 (i, j) 时,distance[i, j] 的值小于等于 count,那么我们可以进行回溯,不必继续搜索下去。

    private int[] idx = {-1, 0, 1, 0, -1};

    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        int[][] distence = new int[maze.length][maze[0].length];
        for (int i = 0; i < maze.length; i++) {
            Arrays.fill(distence[i], Integer.MAX_VALUE);
        }
        distence[start[0]][start[1]] = 0;
        dfs(maze, start[0], start[1], destination, 0, distence);
        return distence[destination[0]][destination[1]] == Integer.MAX_VALUE
                   ? -1 : distence[destination[0]][destination[1]];
    }

    private void dfs(int[][] maze, int x, int y, int[] destination, int count, int[][] distence) {
        for (int k = 0; k < 4; k++) {
            int newCount = count;
            int nx = x + idx[k];
            int ny = y + idx[k + 1];
            while (nx >= 0 && ny >= 0 && nx < maze.length && ny < maze[0].length && maze[nx][ny] == 0) {
                newCount++;
                nx = nx + idx[k];
                ny = ny + idx[k + 1];
            }
            nx = nx - idx[k];
            ny = ny - idx[k + 1];
            if (newCount<distence[nx][ny]){
                distence[nx][ny] = newCount;
                dfs(maze, nx, ny, destination, newCount, distence);
            }
        }
    }

BFS:在一般的广度优先搜索中,我们不会经过同一个节点超过一次,但在这道题目中,只要从起始位置到当前节点的步数 count 小于之前记录的最小步数 distance[i, j],我们就会把 (i, j) 再次加入队列中。

    private int[] idx = {-1, 0, 1, 0, -1};
    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        int[][] distence = new int[maze.length][maze[0].length];
        for (int i = 0; i < maze.length; i++) {
            Arrays.fill(distence[i], Integer.MAX_VALUE);
        }
        distence[start[0]][start[1]] = 0;
        Queue<int[]> q = new LinkedList<>();
        q.add(new int[]{start[0], start[1]});
        while (!q.isEmpty()) {
            int[] curr = q.poll();
            int x = curr[0];
            int y = curr[1];
            for (int k = 0; k < 4; k++) {
                int newCount = distence[x][y];
                int nx = x + idx[k];
                int ny = y + idx[k + 1];
                while (nx >= 0 && ny >= 0 && nx < maze.length && ny < maze[0].length && maze[nx][ny] == 0) {
                    newCount++;
                    nx = nx + idx[k];
                    ny = ny + idx[k + 1];
                }
                nx = nx - idx[k];
                ny = ny - idx[k + 1];
                if (newCount < distence[nx][ny]) {
                    distence[nx][ny] = newCount;
                    q.add(new int[]{nx, ny});
                }
            }
        }
        return distence[destination[0]][destination[1]] == Integer.MAX_VALUE
                   ? -1 : distence[destination[0]][destination[1]];
    }
原文地址:https://www.cnblogs.com/xym4869/p/13390379.html