题目重点:只能前进和转向,探索未知迷宫;失败分支恢复进入位置及朝向,成功留在目标。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练move()尝试当前朝向前进、turn_right旋90度、is_target检测当前位置;初始朝向定义为本地north,不需知道真实世界朝向。
- 静态可逆4邻接,成功停止目标,失败恢复初始位置/朝向。不是Robot Cleaner清洁所有格的合同,成功不能总回原位。
解题路线
- DFS保存逻辑coord与当前heading,每个格按转向尝试四方向。每一轮实际robot转右,同时逻辑heading+1,两者始终一致。
- 走到未见邻格后递归,若失败child调用保证在child位置且朝向等于进入朝向;父goBack转两次、前进一步、再转两次,返回父位置并保持原探索朝向。
- 父随后再转一次尝试下方向,四轮失败后总旋转一整圈,恢复函数入口方向。seen只在成功进格后登记,不能用不确定实际位置猜坐标。
- 递归子调用成功直接return True,不执行goBack或多余转向;一路向上短路,使实际机器人停在目标,而不是例行清洁式统一回退。
- 示例递归便于说明不变量,长走廊可能超过Python栈限制;生产或大约束需显式frame存方向索引,不能声称现示例处理无限深。
手动走一遍
机器人进入东侧支路时面向东,child找不到目标后面向东留在child;goBack转到西、move回父、再转东,下一轮父turn_right变南。若child找到目标,所有父调用直接返回,保持目标位置。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
DIRECTIONS=((-1,0),(0,1),(1,0),(0,-1))
def find_target(robot):
"""move()->bool, turn_right(), is_target(); no grid/heading access.
Start heading is abstract local north. Success stops at target. Failed search
restores both position and heading. Static finite maze, reversible moves.
Recursive baseline may exceed Python recursion limit on a deep corridor.
"""
seen=set()
def backtrack():
robot.turn_right();robot.turn_right()
if not robot.move():raise RuntimeError('backtracking blocked')
robot.turn_right();robot.turn_right()
def search(r,c,heading):
seen.add((r,c))
if robot.is_target():return True
for _ in range(4):
dr,dc=DIRECTIONS[heading];next=(r+dr,c+dc)
if next not in seen and robot.move():
if search(*next,heading):return True
backtrack()
robot.turn_right();heading=(heading+1)%4
return False
return search(0,0,0)
复杂度
O(V+E)探索,4格度数使移动/旋转O(V),seen O(V)、递归栈O(h)最坏V。找一个目标不是最短路径;黑盒移动时间与转向开销可另计真实执行成本。
易错点与追问
容易失分的边界
- 只恢复位置没有恢复朝向,后续方向坐标全错。
- 所有返回都goBack会把成功机器带离目标。
- 假设起点真实朝向north而没有API,不必要且错误;相对坐标足够。
继续深挖
- turn_left和turn_right都可用时,怎样降低回退旋转但保留证明?
- 机器人move可能暂时失败而非墙时,需要怎样区分重试和不可达?
