0874-模拟行走机器人

Raphael Liu Lv10

机器人在一个无限大小的 XY 网格平面上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令 commands

  • -2 :向左转 90
  • -1 :向右转 90
  • 1 <= x <= 9 :向前移动 x 个单位长度

在网格上有一些格子被视为障碍物 obstacles 。第 i 个障碍物位于网格点 obstacles[i] = (xi, yi)

机器人无法走到障碍物上,它将会停留在障碍物的前一个网格方块上,并继续执行下一个命令。

返回机器人距离原点的 最大欧式距离平方 。(即,如果距离为 5 ,则返回 25

注意:

  • 北方表示 +Y 方向。
  • 东方表示 +X 方向。
  • 南方表示 -Y 方向。
  • 西方表示 -X 方向。
  • 原点 [0,0] 可能会有障碍物。

示例 1:

**输入:** commands = [4,-1,3], obstacles = []
**输出:** 25
**解释:** 机器人开始位于 (0, 0):
1. 向北移动 4 个单位,到达 (0, 4)
2. 右转
3. 向东移动 3 个单位,到达 (3, 4)
距离原点最远的是 (3, 4) ,距离为 32 + 42 = 25

示例 2:

**输入:** commands = [4,-1,4,-2,4], obstacles = [[2,4]]
**输出:** 65
**解释** :机器人开始位于 (0, 0):
1. 向北移动 4 个单位,到达 (0, 4)
2. 右转
3. 向东移动 1 个单位,然后被位于 (2, 4) 的障碍物阻挡,机器人停在 (1, 4)
4. 左转
5. 向北走 4 个单位,到达 (1, 8)
距离原点最远的是 (1, 8) ,距离为 12 + 82 = 65

示例 3:

**输入:** commands = [6,-1,-1,6], obstacles = []
**输出:** 36
**解释:** 机器人开始位于 (0, 0):
1. 向北移动 6 个单位,到达 (0, 6).
2. 右转
3. 右转
4. 向南移动 6 个单位,到达 (0, 0).
机器人距离原点最远的点是 (0, 6),其距离的平方是 62 = 36 个单位。

提示:

  • 1 <= commands.length <= 104
  • commands[i] 的值可以取 -2-1 或者是范围 [1, 9] 内的一个整数。
  • 0 <= obstacles.length <= 104
  • -3 * 104 <= xi, yi <= 3 * 104
  • 答案保证小于 231

方法一:哈希表

思路与算法

题目给出一个在点 (0, 0) ,并面向北方的机器人。现在有一个大小为 n 的命令数组 commands 来操作机器人的移动,和一个大小为 m 的障碍物数组 obstacles。现在我们通过 commands 来模拟机器人的移动,并用一个哈希表来存储每一个障碍物放置点。当机器人的指令为向前移动时,我们尝试往前移动对应的次数——若往前一个单位不为障碍物放置点(即不在哈希表中),则机器人向前移动一个单位,否则机器人保持原位不变。

在机器人移动的过程中记录从原点到机器人所有经过的整数路径点的最大欧式距离的平方即为最后的答案。

在代码实现的过程中,对于机器人转向和向前移动的操作,我们可以用一个方向数组 dirs} = {[-1, 0], [0, 1], [1, 0], [0, -1]\ 来现实。若当前机器人的坐标为 (x, y),当前方向的标号为 d,则往前移动一单位的操作为 x = x + \textit{dirs}[d][0],y = y + \textit{dirs}[i][1]。向左转的操作为 d = (d + 3) \mod 4,向右转的操作为 d = (d + 1) \mod 4。

代码

[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int:
dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]]
px, py, d = 0, 0, 1
mp = set([tuple(i) for i in obstacles])
res = 0
for c in commands:
if c < 0:
d += 1 if c == -1 else -1
d %= 4
else:
for i in range(c):
if tuple([px + dirs[d][0], py + dirs[d][1]]) in mp:
break
px, py = px + dirs[d][0], py + dirs[d][1]
res = max(res, px * px + py * py)
return res
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public int robotSim(int[] commands, int[][] obstacles) {
int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int px = 0, py = 0, d = 1;
Set<Integer> set = new HashSet<Integer>();
for (int[] obstacle : obstacles) {
set.add(obstacle[0] * 60001 + obstacle[1]);
}
int res = 0;
for (int c : commands) {
if (c < 0) {
d += c == -1 ? 1 : -1;
d %= 4;
if (d < 0) {
d += 4;
}
} else {
for (int i = 0; i < c; i++) {
if (set.contains((px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
break;
}
px += dirs[d][0];
py += dirs[d][1];
res = Math.max(res, px * px + py * py);
}
}
}
return res;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Solution {
public int RobotSim(int[] commands, int[][] obstacles) {
int[][] dirs = {new int[]{-1, 0}, new int[]{0, 1}, new int[]{1, 0}, new int[]{0, -1}};
int px = 0, py = 0, d = 1;
ISet<int> set = new HashSet<int>();
foreach (int[] obstacle in obstacles) {
set.Add(obstacle[0] * 60001 + obstacle[1]);
}
int res = 0;
foreach (int c in commands) {
if (c < 0) {
d += c == -1 ? 1 : -1;
d %= 4;
if (d < 0) {
d += 4;
}
} else {
for (int i = 0; i < c; i++) {
if (set.Contains((px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
break;
}
px += dirs[d][0];
py += dirs[d][1];
res = Math.Max(res, px * px + py * py);
}
}
}
return res;
}
}
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int px = 0, py = 0, d = 1;
unordered_set<int> mp;
for (auto &obstacle : obstacles) {
mp.emplace(obstacle[0] * 60001 + obstacle[1]);
}
int res = 0;
for (int c : commands) {
if (c < 0) {
d += c == -1 ? 1 : -1;
d %= 4;
if (d < 0) {
d += 4;
}
} else {
for (int i = 0; i < c; i++) {
if (mp.count((px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
break;
}
px += dirs[d][0];
py += dirs[d][1];
res = max(res, px * px + py * py);
}
}
}
return res;
}
};
[sol1-Go]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func robotSim(commands []int, obstacles [][]int) int {
dirs := [][]int{{-1, 0}, {0, 1}, {1, 0}, {0, -1}}
px, py, d := 0, 0, 1
set := make(map[int]bool)
for _, obstacle := range obstacles {
set[obstacle[0] * 60001 + obstacle[1]] = true
}
res := 0
for _, c := range commands {
if c < 0 {
if c == -1 {
d = (d + 1) % 4
} else {
d = (d + 3) % 4
}
} else {
for i := 0; i < c; i++ {
if set[(px + dirs[d][0]) * 60001 + py + dirs[d][1]] {
break
}
px += dirs[d][0]
py += dirs[d][1]
res = max(res, px * px + py * py)
}
}
}
return res
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var robotSim = function(commands, obstacles) {
const dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]];
let px = 0, py = 0, d = 1;
let set = new Set();
for (const obstacle of obstacles) {
set.add(obstacle[0] * 60001 + obstacle[1]);
}
let res = 0;
for (const c of commands) {
if (c < 0) {
d += c == -1 ? 1 : 3;
d %= 4;
} else {
for (let i = 0; i < c; i++) {
if (set.has((px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
break;
}
px += dirs[d][0];
py += dirs[d][1];
res = Math.max(res, px * px + py * py);
}
}
}
return res;
}
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
typedef struct {
int key;
UT_hash_handle hh;
} HashItem;

HashItem *hashFindItem(HashItem **obj, int key) {
HashItem *pEntry = NULL;
HASH_FIND_INT(*obj, &key, pEntry);
return pEntry;
}

bool hashAddItem(HashItem **obj, int key) {
if (hashFindItem(obj, key)) {
return false;
}
HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));
pEntry->key = key;
HASH_ADD_INT(*obj, key, pEntry);
return true;
}

void hashFree(HashItem **obj) {
HashItem *curr = NULL, *tmp = NULL;
HASH_ITER(hh, *obj, curr, tmp) {
HASH_DEL(*obj, curr);
free(curr);
}
}

int robotSim(int* commands, int commandsSize, int** obstacles, int obstaclesSize, int* obstaclesColSize) {
int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int px = 0, py = 0, d = 1;
HashItem *mp = NULL;
for (int i = 0; i < obstaclesSize; i++) {
hashAddItem(&mp, obstacles[i][0] * 60001 + obstacles[i][1]);
}
int res = 0;
for (int i = 0; i < commandsSize; i++) {
int c = commands[i];
if (c < 0) {
d += c == -1 ? 1 : -1;
d %= 4;
if (d < 0) {
d += 4;
}
} else {
for (int i = 0; i < c; i++) {
if (hashFindItem(&mp , (px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
break;
}
px += dirs[d][0];
py += dirs[d][1];
res = fmax(res, px * px + py * py);
}
}
}
hashFree(&mp);
return res;
}

复杂度分析

  • 时间复杂度:O(C \times n + m),其中 n 为数组 commands 的大小,C 为每次可以向前的步数最大值,在该题目中 C = 9,m 为数组 obstacles 的大小。时间开销主要为模拟机器人移动和哈希表存储每一个障碍物的坐标的开销。
  • 空间复杂度:O(m),其中 m 为数组 obstacles 的大小,主要为哈希表存储 obstacles 的空间开销。
 Comments
On this page
0874-模拟行走机器人