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,?] 的时候还是能够正常找到,因此类似情况不会影响代码的正确性。

另一个编译上的问题:https://stackoverflow.com/questions/5973427/error-passing-xxx-as-this-argument-of-xxx-discards-qualifiers

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);
 */

 

posted @ 2018-11-20 13:12  約束の空  阅读(272)  评论(0)    收藏  举报