A robot on an infinite grid starts at point (0, 0) and faces north. The robot can receive one of three possible types of commands:
-2
: turn left 90 degrees-1
: turn right 90 degrees1 <= x <= 9
: move forwardx
units
Some of the grid squares are obstacles.
The i
-th obstacle is at grid point (obstacles[i][0], obstacles[i][1])
If the robot would try to move onto them, the robot stays on the previous grid square instead (but still continues following the rest of the route.)
Return the square of the maximum Euclidean distance that the robot will be from the origin.
Example 1:
Input: commands = [4,-1,3], obstacles = []
Output: 25
Explanation: robot will go to (3, 4)
Example 2:
Input: commands = [4,-1,4,-2,4], obstacles = [[2,4]]
Output: 65
Explanation: robot will be stuck at (1, 4) before turning left and going to (1, 8)
Note:
0 <= commands.length <= 10000
0 <= obstacles.length <= 10000
-30000 <= obstacle[i][0] <= 30000
-30000 <= obstacle[i][1] <= 30000
- The answer is guaranteed to be less than
2 ^ 31
.
這道題說在一個無限大的方格中,原點位置有一個面朝北方的機器人,可以接受三種不同的指令,-2 表示左轉 90 度,-1 表示右轉 90 度,正數表示沿當前方向前進該正數步,然后給了一個障礙數組,就是機器人無法通過的地方,比如當前機器人面前有個障礙物,此時機器人接到的指令是前進x步,但是由於障礙物的因素,該指令無法執行,機器人呆在原地不動。只有接到轉向的命令,才有可能離開當前位置。好,理解了題意之后,來思考如何解題,說到底還是一道迷宮遍歷的題目,但是跟以往不同的是,這里我們並不知道迷宮的大小,而且也沒有目標點需要到達,唯一需要做的就是執行指令,當指令執行完了之后,搜索也就停止了,需要找出的是機器人能到達的距離原點最遠的距離。首先對於障礙物,由於肯定要經常的查找下一個位置是否有障礙物,那么就用一個 HashSet 將所有的障礙物位置存進去,由於坐標是二維的,可以進行降維處理,之前我們都是進行 i*n+j 的降維處理,這里由於不知道迷宮的大小,所以只能換一種方式,可以將橫縱坐標都轉為字符串,然后在中間加個短橫桿隔開,這樣就可以把二維坐標變為一個字符串,放到 HashSet 中了。然后就是處理所有的命令了,在傳統的迷宮遍歷中,使用了方向數組,來控制遍歷的方向,這里也是同樣需要的,但稍有不同的是,這里方向的順序也有講究,因為機器人的初始狀態是朝北的,所以方向數組的第一個應該是朝北走,上北下南左西右東,這樣方向數組的順序應該是上右下左。用一個變量 idx 來表示方向數組中的當前坐標,那么當遇到 -1,即右轉時,idx 自增1即可,為了防止越界,需要對4取余。同理,當遇到 -2,即左轉時,idx 自減1即可,同樣為了防止越界,先加4,再對4取余。當遇到正數命令時,此時就該前進了,用兩個變量x和y分別表示當前位置的橫縱坐標,均初始化為0,分別加上方向數組中對應位置的值,就是下一個位置的坐標了,在經典的迷宮遍歷問題中,我們都會檢驗新位置是否越界,以及是否訪問過,而這里不存在越界的問題,訪沒訪問過也無所謂,重要是看有沒有障礙物,到 HashSet 中去查找一下,若沒有障礙物,則可以到達,更新x和y為新的位置,繼續 while 循環即可。當每個命令執行完了之后,都用當前的x和y距離原點的距離更新一個結果 res 即可,參見代碼如下:
解法一:
class Solution {
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
int res = 0, x = 0, y = 0, idx = 0;
unordered_set<string> obs;
for (auto a : obstacles) obs.insert(to_string(a[0]) + "-" + to_string(a[1]));
vector<int> dirX{0, 1, 0, -1}, dirY{1, 0, -1, 0};
for (int command : commands) {
if (command == -1) idx = (idx + 1) % 4;
else if (command == -2) idx = (idx - 1 + 4) % 4;
else {
while (command-- > 0 && !obs.count(to_string(x + dirX[idx]) + "-" + to_string(y + dirY[idx]))) {
x += dirX[idx];
y += dirY[idx];
}
}
res = max(res, x * x + y * y);
}
return res;
}
};
下面這種解法跟上面沒有什么區別,就是集合的保存類型稍有不同,上面的解法中我們對二維坐標壓縮成了字符串,這里直接用個 pair 對兒來保存橫縱坐標,需要注意的是,使用 pair 對兒的話就不能用 HashSet 了,只能用 TreeSet,其余地方基本不變,參見代碼如下:
解法二:
class Solution {
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
int res = 0, x = 0, y = 0, idx = 0;
set<pair<int, int>> obs;
for (auto a : obstacles) obs.insert({a[0], a[1]});
vector<int> dirX{0, 1, 0, -1}, dirY{1, 0, -1, 0};
for (int command : commands) {
if (command == -1) idx = (idx + 1) % 4;
else if (command == -2) idx = (idx - 1 + 4) % 4;
else {
while (command-- > 0 && !obs.count({x + dirX[idx], y + dirY[idx]})) {
x += dirX[idx];
y += dirY[idx];
}
}
res = max(res, x * x + y * y);
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/874
類似題目:
參考資料:
https://leetcode.com/problems/walking-robot-simulation/
https://leetcode.com/problems/walking-robot-simulation/discuss/152322/Maximum!-This-is-crazy!
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)