题目描述
思路解析
一句话答案:LeetCode 874 模拟行走机器人:方向数组管左右转、障碍放哈希集合让查挡降到 O(1)、每走一步就刷新离原点距离平方,一趟模拟到底,时间 O(n+k)、空间 O(m)。
机器人在网格上按指令走,最后要返回什么
机器人从 [0,0] 出发、面朝北,读一串 commands:-2 左转 90 度,-1 右转 90 度,正数 x 朝当前方向前进 x 步;途中撞障碍就停在原地、该指令剩余步数作废。要返回一路离原点最远那刻的欧氏距离平方。题面 commands=[4,-1,4,-2,4]、obstacles=[[2,4]] 时答案 65。
障碍逐个比对,为什么步数一多就拖垮
前进时每走一格都要先答「下一格是不是障碍」。若把障碍堆成列表、每步拿坐标逐个比对,前进步数和障碍数都可能上万,最坏是步数乘障碍数次比较,规模一大就拖垮。这每步都问的查询,得压到常数时间。
转向、查挡、记距离,这道题就三件事各管一段
先说转向。北、东、南、西按顺时针排成一圈,用下标 k 指当前朝向:右转(-1)让 k 加 1、左转(-2)让 k 加 3、都对 4 取模——下标转满一圈就回到 0,这就是对 4 取模;加 3 即往回退一格,用加法绕开负数取模。再配方向数组 dirs=(0,1,0,-1,0),位移取 (dirs[k], dirs[k+1]),下标 0 朝北、1 朝东,往下是南、西。
查挡靠哈希集合:障碍坐标 (x,y) 全塞进集合,只管在不在、平均查询 O(1),前进前算出下一格、问它在不在集合里。记平方而非距离,是因欧氏距离要开平方根、会引浮点误差,而只比谁更远时平方与距离顺序一致,索性存 x²+y²、既是答案又免开方。
转向改下标、前进逐格探,一步一刷新最远值
主循环逐条读指令。遇 -2 或 -1 只动下标 k,人不挪、最远值不变。遇正数 x 就重复 x 次:按朝向算出下一格、查集合是不是障碍;是就立刻停、跳出这条剩余步数;不是才走过去更新坐标,并马上用 x²+y² 和已记最远值取大。关键在「马上」:最远点可能就在撞墙前那步,走完整条再算就漏了。
[4,-1,4,-2,4]、障碍 [2,4] 一步步走到 65
起点 [0,0] 朝北,ans=0,集合只有 (2,4)。第一条 4:朝北走 4 步,依次到 [0,1]、[0,2]、[0,3]、[0,4],ans 刷成 1、4、9、16。第二条 -1:右转,北转东,人不动,ans 仍 16。
第三条 4:朝东走。第一步到 [1,4],ans=1²+4²=17;第二步下一格 [2,4] 是障碍,停在 [1,4]、剩 3 步作废,ans 保持 17。第四条 -2:左转回北。第五条 4:朝北走 4 步经 [1,5]、[1,6]、[1,7] 到 [1,8],ans 依次刷成 26、37、50、65,终点即最远,答案 65。
-2 和 -1 记反,整条路线跟着偏到别处
最常见的错是把 -2 当右转、-1 当左转,方向一反、之后位移全错,记牢 -2 左、-1 右。撞障碍别把后面指令全丢,作废的只这条前进,人停原地、后续照常执行,绕过后可能走更远。还有个隐蔽的:走完整条才算距离,漏掉半路被挡时更靠外的落点。
复杂度:n 条指令扫一遍、前进总步数记作 k、每步查障碍 O(1),时间 O(n+k);空间在障碍集合、O(m)。全是转向没前进时人在原点、答案 0;第一条前进第一格就撞障碍、没迈一步,同样 0。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记住这套「转向改下标、前进逐格查障碍、每步刷新最远距离平方」,下面每一帧都在套它。
开局:机器人在原点 [0,0](紫色箭头朝北 ↑),红色 ▦ 是障碍 [2,3]。最远距离平方 ans 先记 0,下面开始读指令。
先认舞台:横向是 x(向右增大、即东,◎ 标的就是右边一格),纵向是 y(向上增大、即北)。四个朝向按「北 东 南 西」排成一圈,机器人现在朝北,右转顺时针挪一格、左转逆时针挪一格。
第 1 条指令是 3,朝 北 ↑ 前进 3 步,一步步走。第 1 步:先探前方一格 [0,1](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方没障碍,真走过去,到达 [0,1]。算一下 dist² = 0² + 1² = 1,比旧的最远还大,刷新 ans = 1。
第 2 步:先探前方一格 [0,2](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方没障碍,真走过去,到达 [0,2]。算一下 dist² = 0² + 2² = 4,比旧的最远还大,刷新 ans = 4。
第 3 步:先探前方一格 [0,3](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方没障碍,真走过去,到达 [0,3]。算一下 dist² = 0² + 3² = 9,比旧的最远还大,刷新 ans = 9。
第 2 条指令是 -1,右转 90 度。朝向从 北 ↑ 转到 东 →(箭头跟着转),下标 k 往后挪一格。机器人原地不动,ans 仍是 9。
第 3 条指令是 2,朝 东 → 前进 2 步,一步步走。第 1 步:先探前方一格 [1,3](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方没障碍,真走过去,到达 [1,3]。算一下 dist² = 1² + 3² = 10,比旧的最远还大,刷新 ans = 10。
第 2 步:先探前方一格 [2,3](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方 [2,3] 是障碍 ▦,走不过去。机器人停在 [1,3] 不动,这条指令剩下的步数全部作废,直接去下一条指令。ans 保持 10。
第 4 条指令是 -2,左转 90 度。朝向从 东 → 转到 北 ↑(箭头跟着转),下标 k 往回挪一格(加 3 再对 4 取模)。机器人没移动,ans 还是 10。
第 5 条指令是 1,朝 北 ↑ 前进 1 步,一步步走。第 1 步:先探前方一格 [1,4](◎ 标记),查它在不在障碍集合里,再决定走不走。
前方没障碍,真走过去,到达 [1,4]。算一下 dist² = 1² + 4² = 17,比旧的最远还大,刷新 ans = 17。
全程走完,机器人最后停在 [1,4]。一路上离原点最远的那一刻就在这里,dist² = 1² + 4² = 17,这就是答案 17。
边界先想清:没动作、纯转向、一出门就被挡,三种情况答案都是 0。
两个高频追问:方向数组的好处、以及用哈希集合把判障做到 O(1)。
参考代码
from __future__ import annotationsfrom typing import *from collections import *from functools import *from itertools import *from math import *from heapq import *from bisect import *class Solution: def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: dirs = (0, 1, 0, -1, 0) s = {(x, y) for x, y in obstacles} ans = k = 0 x = y = 0 for c in commands: if c == -2: k = (k + 3) % 4 elif c == -1: k = (k + 1) % 4 else: for _ in range(c): nx, ny = x + dirs[k], y + dirs[k + 1] if (nx, ny) in s: break x, y = nx, ny ans = max(ans, x * x + y * y) return ans复杂度
- 时间:O(n + k),n 条指令依次执行,前进总步数加起来记 k,每步查障碍 O(1)
- 空间:O(m),m 个障碍存进哈希集合,方便 O(1) 判断某格是不是障碍
易错点
面试追问把动画讲成自己的话
追问为什么用方向数组,而不是写四个 if-else 判断东南西北?
追问障碍可能有上万个,怎么快速判断某一格是不是障碍?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
查找和替换模式
LeetCode 890 · 中等 · 沿着 数组套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题