力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0)。小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动。指令有两种:
U: 向y轴正方向移动一格
R: 向x轴正方向移动一格。
不幸的是,在 xy 平面上还有一些障碍物,他们的坐标用obstacles表示。机器人一旦碰到障碍物就会被损毁。
给定终点坐标(x, y),返回机器人能否完好地到达终点。如果能,返回true;否则返回false。
示例 1:
输入:command = "URR", obstacles = [], x = 3, y = 2 输出:true 解释:U(0, 1) -> R(1, 1) -> R(2, 1) -> U(2, 2) -> R(3, 2)。
示例 2:
输入:command = "URR", obstacles = [[2, 2]], x = 3, y = 2 输出:false 解释:机器人在到达终点前会碰到(2, 2)的障碍物。
示例 3:
输入:command = "URR", obstacles = [[4, 2]], x = 3, y = 2 输出:true 解释:到达终点后,再碰到障碍物也不影响返回结果。
限制:
1. 2 <= command的长度 <= 1000 2. command由U,R构成,且至少有一个U,至少有一个R 3. 0 <= x <= 1e9, 0 <= y <= 1e9 4. 0 <= obstacles的长度 <= 1000 5. obstacles[i]不为原点或者终点
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/programmable-robot
这道题目一开始我的思路是模拟机器人的行走过程,然后在机器人每走一步之后判断其是否在障碍点,是否抵达了终点…但我想这样可能会超出时间限制,但我还是想写出来试试,果不其然,超出时间限制!
1234567891011121314151617181920 | class : def robot(self, command: str, obstacles: List[List[int]], x: int, y: int) -> bool: if x == 0 and y == 0: return True x0 = y0 = 0 while(True): for ch in command: if ch == 'U': y0 += 1 else: x0 += 1 for obs in obstacles: if obs[0] > x0 or obs[1] > y0: continue if obs == [x0, y0]: return False # 抵达终点 if x0 == x and y0 == y: return True |
之后我想着机器人行走路径中的点必然有一种规律,这样题目才可能得以简化,我一开始是想把终点和所有障碍点通过某种方式使之等价于单次循环中机器人可能经过的点,我觉得方向是没错的,但在编程的时候又把问题复杂化了,所以一直没调试出来。
然后看了题解中大佬们的解答,总结出两种方法。一是我们可以根据command推算出机器人的行走路径,比如command=’URR’,我们可以推算出如下坐标:
(0,1), (1,1), (2,1)
(2,2), (3,2), (4,2)
(4,3), (5,3), (6,3)…以此类推
从上面我们发现
(3,2) - (1,1) = (2,1);
(4,3) - (0,1) = (4,2);
(6,3) - (2,1) = (4,2);
上面式子的结果都是完整执行一次command命令之后坐标点的倍数。因此判断某个点p是否在行走路径上的条件是:
(pos[0] == p[0] and pos[1] == p[1]) or (pos[1] != p[0] and (p[0]-pos[0])/(p[1]-pos[1]) == divpos[0]/divpos[1])
其中pos是单次循环机器人所走过的坐标中的一点,divpos是完整执行一次command命令之后的坐标点。
而机器人能完好到达终点的条件是:(1)终点坐标在行动轨迹上;(2)在到达终点之前没有障碍点在行动轨迹上
123456789101112131415161718192021222324252627 | class : def robot(self, command: str, obstacles: List[List[int]], x: int, y: int) -> bool: if x == 0 and y == 0: return True ori, oripos = [0, 0], [] for ch in command: if ch == 'R': ori[0] += 1 else: ori[1] += 1 oripos.append(ori[:]) divpos = oripos[-1] # 判断终点是否在行走路径上 for pos in oripos: if (pos[0] == x and pos[1] == y) or (pos[1] != y and (x-pos[0])/(y-pos[1]) == divpos[0]/divpos[1]): break else: return False # 判断障碍物是否在行走路径上 for obs in obstacles: # 障碍物超出终点 if obs[0] > x or obs[1] > y: continue for pos in oripos: # 判断某个障碍物是否在行走路径上 if (pos[0] == obs[0] and pos[1] == obs[1]) or (pos[1] != obs[1] and (obs[0]-pos[0])/(obs[1]-pos[1]) == divpos[0]/divpos[1]): return False return True |
第二种解法是我们可以通过上面所讲的规律找到接近终点和障碍点的某个点,以这个点为起始我们可以在单次循环中判断终点和障碍点是否在行走路径上。比如对于command=’URR’,在如下坐标点中:
(0,1),(1,1),(2,1)
(2,2),(3,2),(4,2)
(4,3),(5,3),(6,3)
(2,1)是接近(2,2),(3,2),(4,2)三个点的坐标,(4,2)是接近(4,3),(5,3),(6,3)三个点的坐标,也就是(2,1),(4,2)都是(2,1)的倍数,具体求解方法请看代码中get_floor_xy()函数。
123456789101112131415161718192021222324252627282930313233343536373839404142434445 | class : def __init__(self): self.unit_x = 0 self.unit_y = 0 # command指令单循环一次 def init_unit(self, command): for ch in command: if ch == 'R': self.unit_x += 1 else: self.unit_y += 1 # 获得在行走路径中最接近[x, y]的路径点 def get_floor_xy(self, x, y): # command至少有一个U和R,所以不必担心除数为0 min_rate = min(x // self.unit_x, y // self.unit_y) return min_rate * self.unit_x, min_rate * self.unit_y # 判断某个点是否在行走路径上 def on_the_way(self, command, x1, y1): x0, y0 = self.get_floor_xy(x1, y1) if x0 == x1 and y0 == y1: return True # 判断单次循环下,是否途径目标点 for ch in command: if ch == 'R': x0 += 1 else: y0 += 1 if x0 == x1 and y0 == y1: return True else: return False def robot(self, command: str, obstacles: List[List[int]], x: int, y: int) -> bool: self.init_unit(command) # 判断终点是否在行走路径上 if not self.on_the_way(command, x, y): return False # 判断障碍点是否在行走路径上 for obs in obstacles: # 障碍点是否超出了范围 if obs[0] > x or obs[1] > y: continue # 障碍点是否在路径上 if self.on_the_way(command, obs[0], obs[1]): return False return True |
来源:https://www.cnblogs.com/lijianming180/p/12366770.html