加载中...
面试题 08.02-迷路的机器人(Robot in a Grid LCCI)
发表于:2021-12-03 | 分类: 中等
字数统计: 1.1k | 阅读时长: 4分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/robot-in-a-grid-lcci

英文原文

Imagine a robot sitting on the upper left corner of grid with r rows and c columns. The robot can only move in two directions, right and down, but certain cells are "off limits" such that the robot cannot step on them. Design an algorithm to find a path for the robot from the top left to the bottom right.

"off limits" and empty grid are represented by 1 and 0 respectively.

Return a valid path, consisting of row number and column number of grids in the path.

Example 1:

Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: [[0,0],[0,1],[0,2],[1,2],[2,2]]

Note:

  • r, c <= 100

中文题目

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。

网格中的障碍物和空位置分别用 10 来表示。

返回一条可行的路径,路径由经过的网格的行号和列号组成。左上角为 0 行 0 列。如果没有可行的路径,返回空数组。

示例 1:

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: [[0,0],[0,1],[0,2],[1,2],[2,2]]
解释: 
输入中标粗的位置即为输出表示的路径,即
0行0列(左上角) -> 0行1列 -> 0行2列 -> 1行2列 -> 2行2列(右下角)

说明:r 和 c 的值均不超过 100。

通过代码

高赞题解

目标:

找到一条从左上角走到右下角路径,如果没有这样的路径返回空数组。

规则:

从左上角走到右下角,每次只能向下走或者向右走。

明确回溯法四要素:

  1. 结束条件:走到右下角就结束;右下角本身有障碍物,不可能走得到;
  2. 路径:走到当前位置之前已经走过的路径。
  3. 选择:每次只能向下走或者向右走。当下方有障碍物时,只能考虑向右走;当右方有障碍物时,只能考虑向下走;当下方和右方都有障碍物时,只能往回走,你从哪个地方进入这个死胡同的就回到哪个地方去。
  4. 约束条件:除了在“选择中的”约束之外,我们还不能走已经走过的地方。

代码:

以$x,y$表示当前位置,一个与网格同大小的数组$visit$记录走过的地方。

class Solution {

    List<List<Integer>> path = new LinkedList<>();  // 记录路径
    int r = 0;  // 行数
    int c = 0;  // 列数
    public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {
        r = obstacleGrid.length;
        if (r == 0) {       // 空网格
            return path;
        }
        c = obstacleGrid[0].length;
        if (obstacleGrid[r - 1][c - 1] == 1) {  // 终点有障碍
            return path;
        }
        boolean[][] visit = new boolean[r][c];  // 记录数组
        backtrack(obstacleGrid, 0, 0, visit);
        return path;
    }

    public boolean backtrack(int[][] obstacleGrid, int x, int y, boolean[][] visit) {
        // 越界,有障碍,已访问
        if (x >= r || y >= c || obstacleGrid[x][y] == 1 || visit[x][y]) {
            return false;
        }
        // 如果不是以上情况,说明这个格子值得探索,做出选择
        path.add(Arrays.asList(x, y));
        visit[x][y] = true;
        // 选择后是否到达终点
        if (x == r - 1 && y == c - 1) {
            return true;
        }
        // 选择后没到终点,先尝试向下,再尝试向右,神奇的或运算
        if (backtrack(obstacleGrid, x + 1, y, visit) || backtrack(obstacleGrid, x, y + 1, visit)) {
            return true;
        }
        // 既不能向下也不能向右,是个死胡同,撤销选择
        path.remove(path.size() - 1);
        return false;
    }
}

算法分析:

以$r,c$分别表示网格的行和列。

  1. 遍历一次网格的所有格子,每个格子仅访问一次,时间复杂度为$O(r \times c)$.
  2. 不考虑递归使用栈辅助空间,辅助记录数组$O(r \times c)$,几个变量$O(1)$,$path$链表记录路径$O(r+c-2)=O(r+c)$,因此总的空间复杂度为$O(r \times c)$.

$path$的大小怎么算?

答:对于$r$行$c$列的网格,从左上角出发,每次只能向下或者向右走,要到达右下角,任何路径都要包括$r-1$次向下走,$c-1$次向右走。

如果本文对你有帮助,可以给一个大拇指呀!

waterProblem.png

统计信息

通过次数 提交次数 AC比率
13100 36339 36.0%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
面试题 04.12-求和路径(Paths with Sum LCCI)
下一篇:
面试题 10.01-合并排序的数组(Sorted Merge LCCI)
本文目录
本文目录