leetcode 874 Robot Simulation
leetcode 874 Robot Simulation
限制:32MB, 1s
描述
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 degrees
1 <= x <= 9: move forward x 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.
題解
題目要求在直角坐標系上有一個機器人——姑且看成一個點——在經過旋轉、移動的時候,計算離原點最遠的距離,算出該值的平方值。
從難度來看這是一個easy題,但是主要是因為測例主要是在小範圍的,即使在極端情況下的樣例,也沒有達到最大的復雜度。
在一種可以AC的代碼中,計算每一個移動操作在經過障礙的時候遍歷障礙的時候使用的方法是加步長,而這個步長只是1。那麽如果移動操作給出了10000(符合條件),則要執行10000次這樣的操作,如果在坐標範圍內做(0,0)開始的邊長為10^4的正方形移動,復雜度至少為10^8,計算結果超時了。計算的復雜度包括了:查找障礙,用C++11的hash表降到O(1),但是遍歷障礙的復雜度O (commands.length * obstacles.length)。
這道easy的題的解決方法這樣做沒問題,最優的解法也是這樣做的,但並不能說它就能在極端情況最優了。比較復雜的做法是記錄x軸障礙,y軸障礙的數組,在數組中用二分法找到位置的結果。處理極端情況比上一種做法快了上千倍。當然,二分法有C++的一個庫,可以用來求上下界,lower_bound(x)返回數組中第一個>=x的位置(不存在則返回end),
和upper_bound(x)返回y, y-1的值>=x。
一味追求在leetcode的速度最快是不合理的,一些leetcode的樣例並不能反映問題的復雜度。
代碼
#include<bits/stdc++.h> #include <unordered_set> #define square(x, y) ((x * x) + (y * y)) #define MAXN 10010 using namespace std; bool cmp(const vector<int>& a, const vector<int>& b) { if (a[0] == b[0]) { return a[1] < b[1]; } return a[0] < b[0]; } class Solution { public: friend bool cmp(const vector<int>& a, const vector<int>& b); map<int, vector<int> > pix, piy; int maxdis; typedef map<int, vector<int> > mpv; typedef vector<int> vi; void setValid(int* curx, int* cury, int t, int command) { vector<int> vec; if (t == 0 || t == 2) { vec = pix[*curx]; } else { vec = piy[*cury]; } vi::iterator it; if (t == 0) { it = upper_bound(vec.begin(), vec.end(), *cury); if (it == vec.end() || vec.size() == 0) { *cury = *cury + command; } else { *cury = min(*it - 1, *cury + command); } } else if (t == 2) { it = lower_bound(vec.begin(), vec.end(), *cury); if (vec.size() == 0 || it == vec.begin()) { *cury = *cury - command; } else { *cury = max(*(it - 1) + 1, *cury - command); } } else if (t == 1) { it = upper_bound(vec.begin(), vec.end(), *curx); if (it == vec.end() || vec.size() == 0) { *curx = *curx + command; } else { *curx = min(*it - 1, *curx + command); } } else { it = lower_bound(vec.begin(), vec.end(), *curx); if (vec.size() == 0 || it == vec.begin()) { *curx = *curx - command; } else { *curx = max(*(it - 1) + 1, *curx - command); } } } int robotSim(vector<int>& commands, vector<vector<int> >& obstacles) { pix.clear(); piy.clear(); sort(obstacles.begin(), obstacles.end(), cmp); int tsize = 0; if (obstacles.size() > 0) { tsize = obstacles[0].size(); } int dxy[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; int size = obstacles.size(); int t = 0; int curx = 0, cury = 0; int obx, oby; int dis = 0; maxdis = 0; //max euclidean distance for (int i = 0; i < size; i++) { obx = obstacles[i][0]; oby = obstacles[i][1]; pix[obx].push_back(oby); piy[oby].push_back(obx); } #if 0 cout << "x\n"; for (mpv::iterator it = pix.begin(); it != pix.end(); ++it) { cout << it->first; for (int j = 0; j < it->second.size(); j++) { cout << " " << it->second[j]; } cout << endl; } cout << "y\n"; for (mpv::iterator it = piy.begin(); it != piy.end(); ++it) { cout << it->first; for (int j = 0; j < it->second.size(); j++) { cout << " " << it->second[j]; } cout << endl; } #endif size = commands.size(); for (int i = 0; i < size; i++) { if (commands[i] == -1) { t = (t + 1) % 4; } else if (commands[i] == -2) { t = (t - 1 + 4) % 4; } else { setValid(&curx, &cury, t, commands[i]); dis = square(curx, cury); if (dis > maxdis) { maxdis = dis; } } } return maxdis; } };
leetcode參考解
static auto __ = [] () { ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }(); #define HASH(x, y) (((unsigned long long)(x) << 32) | (unsigned int)(y)) class Solution { public: int robotSim(vector<int>& commands, vector<vector<int> >& obstacles) { unordered_set<unsigned long long> obs_set; for(const auto & a: obstacles) { obs_set.insert(HASH(a[0], a[1])); } int max = 0; int x = 0; int y = 0; int* axis[] = {&y, &x, &y, &x}; int diff[] = {1, 1, -1, -1}; int direct = 0; for (const auto&c: commands) { if(c < 0) { // Turning left and turning right are opposite actions, it‘s good to be -1 and 1. direct += ((c + 1) << 1) + 1; direct &= 3; continue; } int &a = *axis[direct]; int d = diff[direct]; for(int i = 0; i < c; i++) { a += d; if (obs_set.end() != obs_set.find(HASH(x, y))) { a -= d; break; } } int distance = x * x + y * y; if(max < distance) { max = distance; } } return max; } };
參考
theodoreyth. Walking Robot Simulation. https://leetcode.com/problems/walking-robot-simulation/description/. May,2018.
leetcode 874 Robot Simulation