|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[2069. 模拟行走机器人 II](https://leetcode-cn.com/problems/walking-robot-simulation-ii/solution/by-ac_oier-6zib/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「模拟」、「脑筋急转弯」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +给你一个在 `XY` 平面上的 `width x height` 的网格图,左下角 的格子为 $(0, 0),ドル右上角的格子为 $(width - 1, height - 1)$ 。网格图中相邻格子为四个基本方向之一(`"North"`,`"East"`,`"South"` 和 `"West"`)。一个机器人初始在格子 $(0, 0)$ ,方向为 `"East"`。 |
| 10 | + |
| 11 | +机器人可以根据指令移动指定的步数。每一步,它可以执行以下操作。 |
| 12 | + |
| 13 | +1. 沿着当前方向尝试往前一步 。 |
| 14 | +2. 如果机器人下一步将到达的格子超出了边界,机器人会逆时针转 90 度,然后再尝试往前一步。 |
| 15 | + |
| 16 | +如果机器人完成了指令要求的移动步数,它将停止移动并等待下一个指令。 |
| 17 | + |
| 18 | +请你实现 `Robot` 类: |
| 19 | +* `Robot(int width, int height)` 初始化一个 `width x height` 的网格图,机器人初始在 $(0, 0),ドル方向朝 `"East"`。 |
| 20 | +* `void move(int num)` 给机器人下达前进 `num` 步的指令。 |
| 21 | +* `int[] getPos()` 返回机器人当前所处的格子位置,用一个长度为 2ドル$ 的数组 $[x, y]$ 表示。 |
| 22 | +* `String getDir()` 返回当前机器人的朝向,为 `"North"`,`"East"`,`"South"` 或者 `"West"`。 |
| 23 | + |
| 24 | +示例 1: |
| 25 | + |
| 26 | +``` |
| 27 | +输入: |
| 28 | +["Robot", "move", "move", "getPos", "getDir", "move", "move", "move", "getPos", "getDir"] |
| 29 | +[[6, 3], [2], [2], [], [], [2], [1], [4], [], []] |
| 30 | + |
| 31 | +输出: |
| 32 | +[null, null, null, [4, 0], "East", null, null, null, [1, 2], "West"] |
| 33 | + |
| 34 | +解释: |
| 35 | +Robot robot = new Robot(6, 3); // 初始化网格图,机器人在 (0, 0) ,朝东。 |
| 36 | +robot.move(2); // 机器人朝东移动 2 步,到达 (2, 0) ,并朝东。 |
| 37 | +robot.move(2); // 机器人朝东移动 2 步,到达 (4, 0) ,并朝东。 |
| 38 | +robot.getPos(); // 返回 [4, 0] |
| 39 | +robot.getDir(); // 返回 "East" |
| 40 | +robot.move(2); // 朝东移动 1 步到达 (5, 0) ,并朝东。 |
| 41 | + // 下一步继续往东移动将出界,所以逆时针转变方向朝北。 |
| 42 | + // 然后,往北移动 1 步到达 (5, 1) ,并朝北。 |
| 43 | +robot.move(1); // 朝北移动 1 步到达 (5, 2) ,并朝 北 (不是朝西)。 |
| 44 | +robot.move(4); // 下一步继续往北移动将出界,所以逆时针转变方向朝西。 |
| 45 | + // 然后,移动 4 步到 (1, 2) ,并朝西。 |
| 46 | +robot.getPos(); // 返回 [1, 2] |
| 47 | +robot.getDir(); // 返回 "West" |
| 48 | +``` |
| 49 | + |
| 50 | +提示: |
| 51 | +* 2ドル <= width, height <= 100$ |
| 52 | +* 1ドル <= num <= 10^5$ |
| 53 | +* `move`,`getPos` 和 `getDir` 总共调用次数不超过 10ドル^4$ 次。 |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +### 模拟 |
| 58 | + |
| 59 | +根据题目给定的移动规则可知,机器人总是在外圈移动(共上下左右四条),而移动方向分为四类: |
| 60 | + |
| 61 | + |
| 62 | + |
| 63 | +当行走步数为 $mod = 2 * (w - 1) + 2 * (h - 1)$ 的整数倍时,会回到起始位置,因此我们可以通过维护一个变量 `loc` 来记录行走的总步数,并且每次将 `loc` 对 `mod` 进行取模来得到有效步数。 |
| 64 | + |
| 65 | +在回答 `getPos` 和 `getDir` 询问时,根据当前 `loc` 进行分情况讨论(见注释)。 |
| 66 | + |
| 67 | +另外还有一个小细节:根据题意,如果当前处于 $(0, 0)$ 位置,并且没有移动过,方向为 `East`,若移动过,方向则为 `South`,这可以通过一个变量 `moved` 来进行特判处理。 |
| 68 | + |
| 69 | +代码: |
| 70 | +```Java |
| 71 | +class Robot { |
| 72 | + String[] ss = new String[]{"East", "North", "West", "South"}; |
| 73 | + int w, h, loc; // loc: 有效(取模后)移动步数 |
| 74 | + boolean moved; // 记录是否经过移动,用于特判 (0,0) 的方向 |
| 75 | + public Robot(int width, int height) { |
| 76 | + w = width; h = height; |
| 77 | + } |
| 78 | + public void step(int num) { |
| 79 | + moved = true; |
| 80 | + loc += num; |
| 81 | + loc %= 2 * (w - 1) + 2 * (h - 1); |
| 82 | + } |
| 83 | + public int[] getPos() { |
| 84 | + int[] info = move(); |
| 85 | + return new int[]{info[0], info[1]}; |
| 86 | + } |
| 87 | + public String getDir() { |
| 88 | + int[] info = move(); |
| 89 | + int x = info[0], y = info[1], dir = info[2]; |
| 90 | + // 特殊处理当前在 (0,0) 的情况,当未移动过方向为 East,移动过方向为 South |
| 91 | + if (x == 0 && y == 0) return moved ? ss[3] : ss[0]; |
| 92 | + return ss[dir]; |
| 93 | + } |
| 94 | + int[] move() { |
| 95 | + if (loc <= w - 1) { |
| 96 | + // 当移动步数范围在 [0,w-1] 时,所在位置为外圈的下方,方向为 East |
| 97 | + return new int[]{loc, 0, 0}; |
| 98 | + } else if (loc <= (w - 1) + (h - 1)) { |
| 99 | + // 当移动步数范围在 [w,(w-1)+(h-1)] 时,所在位置为外圈的右方,方向为 North |
| 100 | + return new int[]{w - 1, loc - (w - 1), 1}; |
| 101 | + } else if (loc <= 2 * (w - 1) + (h - 1)) { |
| 102 | + // 当移动步数范围在 [(w-1)+(h-1)+1,2*(w-1)+(h-1)] 时,所在位置为外圈的上方,方向为 West |
| 103 | + return new int[]{(w - 1) - (loc - ((w - 1) + (h - 1))), h - 1, 2}; |
| 104 | + } else { |
| 105 | + // 当移动步数范围在 [2*(w-1)+(h-1)+1,2*(w-1)+2*(h-1)] 时,所在位置为外圈的左方,方向为 South |
| 106 | + return new int[]{0, (h - 1) - (loc - (2 * (w - 1) + (h - 1))), 3}; |
| 107 | + } |
| 108 | + } |
| 109 | +} |
| 110 | +``` |
| 111 | +* 时间复杂度:$O(1)$ |
| 112 | +* 空间复杂度:$O(1)$ |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +### 最后 |
| 117 | + |
| 118 | +这是我们「刷穿 LeetCode」系列文章的第 `No.2169` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 119 | + |
| 120 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 121 | + |
| 122 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 123 | + |
| 124 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 125 | + |
0 commit comments