LeetCode 855. Exam Room
方法一:Set (BST)
Set存放有人的index。
每次坐下时,遍历set找到最大的距离,并且记录位置,离开则直接删除目标数字。
注意一些边界情况和下标即可,最容易遗漏的就是最左边和最右边的位置。
时间复杂度 seat O(n),leave O(logn)
class ExamRoom { public: ExamRoom(int N):n(N){}; int seat() { if (s.size()==0){ s.insert(0); return 0;} int res=0; int max_dis=*s.begin(); int prev=-1; for (int x:s){ if (prev!=-1){ int cur_dis = (x-prev)/2; if (cur_dis>max_dis){ max_dis = cur_dis; res = prev+cur_dis; } } prev = x; } if (n-1-prev>max_dis){ max_dis = n-1-prev; res = n-1; } s.insert(res); return res; } void leave(int p) { s.erase(p); } private: int n; // number of seats set<int> s; // set records the seated seats }; /** * Your ExamRoom object will be instantiated and called as such: * ExamRoom obj = new ExamRoom(N); * int param_1 = obj.seat(); * obj.leave(p); */
方法二:Set (BST) + Unordered_Map (HashMap)
上一种方法如果要优化seat,必须要记录连续空座位的长度,在小于O(n)时间内找到最大距离。
我们可以新建一个interval结构体,根据dist来重载<符号。如果用set作为容器,我们就可以 O(logn) 时间找到最大的距离。
seat以后我们只要将当前interval一分为二重新插入set即可。
关键问题是leave。假设leave(int p),那么我们知道左边的interval是 [?, p-1],右边的interval是 [p+1, ?]。如果我们事先用一个hashtable分别记录了每个interval的左边界和右边界,那么我们就可以在O(1)的时间找到需要合并的两个interval,合并以后插入set,总的时间复杂度为 O(logn)。
特别注意的是,interval里可能会出现 l>r 的情况,比如分割 [1,1] 就会生成 [1,0] [2,1] 的情况,是没有问题的,只要把dist计算为 -1 即可(这样就不会继续被分割)。合并的时候 leave(1),寻找 [?,0] [2,?] 的时候还是能够正常找到,因此类似情况不会影响代码的正确性。
struct Interval{ static int N; int l, r; // [l,r] Interval(int _l, int _r):l(_l),r(_r){} int get_dist() const { // get the dist if (l>r) return -1; if (l==0) return r; if (r==N-1) return r-l; return (r-l)/2; } int get_pos() const { // get the pos to seat if (l==0) return 0; if (r==N-1) return N-1; return l+(r-l)/2; } bool operator<(const Interval &i) const { int d1=get_dist(), d2=i.get_dist(); if (d1!=d2) return d1>d2; else return l<i.l; } }; int Interval::N = 0; class ExamRoom { public: ExamRoom(int N) { Interval::N = N; s.insert(Interval(0,N-1)); l2r[0] = N-1; r2l[N-1] = 0; } int seat() { // split the interval with largest dist Interval cur=*s.begin(); s.erase(s.begin()); int p=cur.get_pos(); s.insert(Interval(cur.l, p-1)); l2r[cur.l]=p-1; r2l[p-1]=cur.l; s.insert(Interval(p+1, cur.r)); l2r[p+1]=cur.r; r2l[cur.r]=p+1; return p; } void leave(int p) { // merge [?,p-1] [p+1,?] int l=r2l[p-1], r=l2r[p+1]; s.erase(Interval(l,p-1)); s.erase(Interval(p+1,r)); s.insert(Interval(l,r)); l2r[l]=r; r2l[r]=l; } private: set<Interval> s; unordered_map<int,int> l2r, r2l; }; /** * Your ExamRoom object will be instantiated and called as such: * ExamRoom* obj = new ExamRoom(N); * int param_1 = obj->seat(); * obj->leave(p); */

浙公网安备 33010602011771号