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.