LeetCode 每日一题笔记
0. 前言
- 日期:2025.04.06
- 题目:874. 模拟行走机器人
- 难度:中等
- 标签:数组 哈希表 模拟
1. 题目理解
问题描述 :
机器人在一个无限大小的 XY 网格平面上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令 commands :
-2 :向左转 90 度
-1 :向右转 90 度
1 <= x <= 9 :向前移动 x 个单位长度
在网格上有一些格子被视为障碍物 obstacles 。第 i 个障碍物位于网格点 obstacles[i] = (xi, yi)。
机器人无法走到障碍物上,它将会停留在障碍物的前一个网格方块上,并继续执行下一个命令。
返回机器人距离原点的 最大欧式距离 的 平方 。
注意:
北方表示 +Y 方向。
东方表示 +X 方向。
南方表示 -Y 方向。
西方表示 -X 方向。
原点 [0,0] 可能会有障碍物。
示例:
输入:commands = [4,-1,3], obstacles = []
输出:25
解释:
机器人开始位于 (0, 0):
- 向北移动 4 个单位,到达 (0, 4)
- 右转
- 向东移动 3 个单位,到达 (3, 4)
距离原点最远的是 (3, 4) ,距离为 3² + 4² = 25
2. 解题思路
核心观察
- 机器人仅有北、东、南、西四个朝向,左转/右转会让朝向循环切换;
- 移动时必须逐格检查障碍物,遇到障碍物立即停止当前移动指令;
- 使用哈希集合存储障碍物坐标,可实现O(1)时间复杂度的障碍物查询;
- 只需记录过程中的最大距离平方,无需计算实际欧式距离。
算法步骤
- 障碍物预处理:将所有障碍物坐标存入哈希集合,方便快速判断;
- 初始化参数:起始坐标(0,0)、初始朝向北方、最大距离平方为0;
- 遍历执行命令 :
- 转向命令:调整机器人的朝向状态;
- 移动命令:按照当前朝向逐格移动,每一步校验是否存在障碍物,无障碍物则更新坐标,同步更新最大距离平方;
- 返回结果:遍历完所有命令后,输出最大距离平方。
3. 代码实现
java
package com.sheeta1998.lec.lc874;
import java.util.HashSet;
import java.util.Set;
class Solution {
public void setAdd(Set<String> set, int a, int b) {
String ad = a + "," + b;
set.add(ad);
}
public boolean setCompare(Set<String> set, int a, int b) {
String cp = a + "," + b;
return !set.contains(cp);
}
public int robotSim(int[] commands, int[][] obstacles) {
int res = 0;
int sta = 1;// 1 北,2东,3南,4西
int x = 0;
int y = 0;
Set<String> set = new HashSet<>();
for (int i = 0; i < obstacles.length; i++) {
setAdd(set, obstacles[i][0], obstacles[i][1]);
}
for (int i = 0; i < commands.length; i++) {
int a = commands[i];
if (a < 0) {
if (a == -1) {
if (sta != 4) {
sta += 1;
} else {
sta = 1;
}
} else {
if (sta != 1) {
sta -= 1;
} else {
sta = 4;
}
}
} else {
if (sta == 1) {
for (int j = 0; j < a; j++) {
if (!setCompare(set, x, y + 1)) {
break;
} else {
y++;
}
}
res= Math.max(res,x*x+y*y);
} else if (sta == 2) {
for (int j = 0; j < a; j++) {
if (!setCompare(set, x + 1, y)) {
break;
} else {
x++;
}
}
res= Math.max(res,x*x+y*y);
} else if (sta == 3) {
for (int j = 0; j < a; j++) {
if (!setCompare(set, x, y - 1)) {
break;
} else {
y--;
}
}
res= Math.max(res,x*x+y*y);
} else {
for (int j = 0; j < a; j++) {
if (!setCompare(set, x - 1, y)) {
break;
} else {
x--;
}
}
res= Math.max(res,x*x+y*y);
}
}
}
return res;
}
}
4. 代码优化说明
优化点1:方向简化
使用二维数组存储四个方向的坐标增量,替代数字状态判断,大幅简化代码逻辑:
java
int[][] dirs = {{0,1},{1,0},{0,-1},{-1,0}}; // 北、东、南、西
int d = 0; // 方向索引
优化点2:障碍物存储优化
使用Long类型替代字符串存储坐标,减少字符串拼接开销,查询效率更高:
java
Set<Long> set = new HashSet<>();
long code = ((long)x << 32) | (y & 0xFFFFFFFFL);
优化点3:精简重复逻辑
合并最大距离更新的代码,消除冗余逻辑。
5. 复杂度分析
-
时间复杂度 :O(M+N×K)O(M + N \times K)O(M+N×K)
- MMM 为障碍物数量,预处理障碍物耗时 O(M)O(M)O(M);
- NNN 为命令数量,KKK 为单次移动的最大步数(9),移动操作总耗时 O(N×K)O(N \times K)O(N×K);
- 障碍物查询为 O(1)O(1)O(1) 操作。
-
空间复杂度 :O(M)O(M)O(M)
- 哈希集合存储障碍物坐标,空间大小与障碍物数量成正比。
6. 总结
- 核心思路是模拟机器人行走 + 哈希表快速查障,严格按照题目规则逐命令执行、逐格移动校验;
- 关键技巧:通过状态标记管理机器人朝向,利用哈希集合解决障碍物查询的效率问题;
- 本题重点考察模拟能力和哈希表的实际应用,无需复杂算法,重点在于逻辑严谨性。
关键点回顾
- 机器人四个朝向循环切换,转向逻辑需处理边界(如北左转→西);
- 移动必须逐格判断,遇到障碍物立即终止当前移动指令;
- 哈希表是解决障碍物快速查询的最优方案。