• 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]];
        }
    
  • 相关阅读:
    linux 信号处理 二 (信号的默认处理)
    linux 信号处理 一 (基本概念)
    POSIX 消息队列 之 参数说明
    System V 消息队列 实例
    KDB支持单步调试功能(ARM架构)
    找工作笔试面试那些事儿(16)---linux相关知识点(1)
    Central Europe Regional Contest 2012 Problem H: Darts
    计算机数据结构之——什么是艺术品?
    老罗android开发视频教程 下载地址
    HTML5 实现拖拽
  • 原文地址:https://www.cnblogs.com/xym4869/p/13390379.html
Copyright © 2020-2023  润新知