题目:机器人大冒险
- 力扣团队买了一个可编程机器人,机器人初始位置在原点
(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
解释:到达终点后,再碰到障碍物也不影响返回结果。
限制:
2 <= command
的长度<= 1000
- command由U,R构成,且至少有一个U,至少有一个R
0 <= x <= 1e9
,0 <= y <= 1e9
0 <= obstacles
的长度<= 1000
obstacles[i]
不为原点或者终点
来源:力扣(LeetCode)LCP.3
链接:https://leetcode-cn.com/problems/programmable-robot
分析:
- 由于x和y最多10亿,一个一个遍历肯定不现实。
- 经过思考发现,我们可以找每一个要找的点的前一行或前一列的最后一个。
- 比如终点为
(x, y)
,我们可以找到x-1或者y-1时的最后一个位置。
- 然后再遍历一遍就能判断是否经过该点。因为
command
至少有一个U和R。
代码:
class Solution {
public boolean robot(String command, int[][] obstacles, int x, int y) {
int dx = 0, dy = 0;
char[] cmd = command.toCharArray(); // 把String转为数组,方便遍历。
for (char c : cmd) { // 算出up和right各有多少个。
if (c == 'U') dy++;
else dx++;
}
int ans = isPassed(cmd, x, y, dx, dy); // 拿到走到终点的次数。
// 先看isPassed函数再往下看。
/*
为什么isPassed要拿到走的总次数而不直接返回true或false呢
比如你发现有一个obstacle是经过的,那么最终答案并不一定是false,
因为如果终点在这个点的前面,那么机器人根本不会走到那个点。答案是true。
*/
if (ans == -1) return false; // 终点都没经过,肯定false
for (int[] obstacle : obstacles) {
int cnt = isPassed(cmd, obstacle[0], obstacle[1], dx, dy);
if (cnt != -1 && cnt < ans) return false;
//不等于-1,说明经过了,然后再看这个点和终点哪个次数多。ans多,说明这个点在ans前面,返回false。
}
return true;
}
// 判断是否经过该点,经过返回走的次数,没经过返回-1。
public int isPassed(char[] cmd, int x, int y, int dx, int dy) {
int round = Math.min(x / dx, y / dy); // 计算走到第x-1或y-1层需要多少轮
int cnt = cmd.length * round; // 前几轮的总次数
dx *= round; dy *= round; // 在第x-1或y-1层时的位置。
if (dx == x && dy == y) return cnt; // 正好就是要找的点,直接返回。
for (char c : cmd) { // 遍历第x层或y层,如果经过,那么答案一定会遍历到。
if (c == 'U') dy++; // 要按command的顺序走
else dx++;
cnt++; // 不要忘了每遍历一次,次数都要加1
if (dx == x && dy == y) return cnt; // 一旦找到,直接返回所需要的次数。
}
return -1;
}
}