In an exam room, there are N
seats in a single row, numbered 0, 1, 2, ..., N-1
.
When a student enters the room, they must sit in the seat that maximizes the distance to the closest person. If there are multiple such seats, they sit in the seat with the lowest number. (Also, if no one is in the room, then the student sits at seat number 0.)
Return a class ExamRoom(int N)
that exposes two functions: ExamRoom.seat()
returning an int
representing what seat the student sat in, and ExamRoom.leave(int p)
representing that the student in seat number p
now leaves the room. It is guaranteed that any calls to ExamRoom.leave(p)
have a student sitting in seat p
.
Example 1:
Input: ["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]] Output: [null,0,9,4,2,null,5] Explanation: ExamRoom(10) -> null seat() -> 0, no one is in the room, then the student sits at seat number 0. seat() -> 9, the student sits at the last seat number 9. seat() -> 4, the student sits at the last seat number 4. seat() -> 2, the student sits at the last seat number 2. leave(4) -> null seat() -> 5, the student sits at the last seat number 5.
Note:
1 <= N <= 10^9
ExamRoom.seat()
andExamRoom.leave()
will be called at most10^4
times across all test cases.- Calls to
ExamRoom.leave(p)
are guaranteed to have a student currently sitting in seat numberp
.
题目大意:一排作为,编号为0到N-1,每次调用seat指令,从当前没有人的座位中挑选一个没有人的座位,使得这个人离其他人的距离最远,如果有多个这样的位置,选择座号最小的。
分析:已经做好的座位,把剩余的空座位分成多个区间,我们选择了一个区间,在区间中增加一个座位,距离最大。
一开始座位都是空,我们模拟两个不能坐的座位,编号-1,N,也就是说一开始只有一个区间。
座位的边界也就是0和N-1需要特殊处理一下。
使用一个优先队列存储所有的区间信息,当seat命令时,从优先队列取出最大的值,更新区间信息。
当leave命令调用是,相当于增加了一个大的区间,之前的两个小区间删除。
需要解决的问题:
1. 如何根据当前离开的座位,快速找到他相邻的两个座位;
2. 优先队列不支持删除任一元素的操作。
这里做了一个trick,使用stl的map,因为他是有序存储的,可以快速定位相邻的座位;另外优先队列存储的是区间的指针值,当需要删除某一个区间的时候,相当于把区间置为不可用即可;另外需要一个辅助的map,快速根据区间端点找到区间信息指针。
seat操作:优先队列弹出以及增加区间的复杂度O(logn),添加元素到set和map的复杂度也是O(logn),所以整个seat操作的时间复杂度为O(logn)
leave操作:set查找和删除logn,map插入也是logn,整个操作的算法复杂度也是logn
代码如下:
struct node {
int st;
int ed;
int valid;
int length;
node(int x = 0, int y = 0, int l = 0){
valid = 1;
st = x;
ed = y;
length = l;
}
};
struct cmp{
bool operator()(node *a, node *b){
if(a->length==b->length) return a->st>b->st;
return a->length<b->length;
}
};
class ExamRoom {
public:
ExamRoom(int N) {
N_ = N;
node *p = new node(-1, N, N);
qe.push(p);
seats.insert(-1);
seats.insert(N);
address[make_pair(-1,N)] = p;
}
~ExamRoom(){
for(auto it = address.begin(); it!=address.end();it++)
{
delete (it->second);
}
}
void add_node(int st, int ed){
auto it = address.find(make_pair(st, ed));
if(it!=address.end()){
it->second->valid = 1;
} else {
int length = (ed-st)/2;
if(st==-1 || ed==N_)length = ed-st-1;
node *p = new node(st, ed, length);
qe.push(p);
address[make_pair(st, ed)] = p;
}
}
int seat() {
if(qe.size()==0) return 0;
while(!qe.empty()){
auto p = qe.top();
qe.pop();
if(p->valid==0) {
auto it = address.find(make_pair(p->st, p->ed));
if(it!=address.end()){
address.erase(it);
delete p;
}
continue;
}
int ret;
if(p->st==-1)
ret = 0;
else if(p->ed==N_)
ret = N_-1;
else{
ret = (p->st+p->ed)/2;
}
if(ret-p->st>1){
add_node(p->st, ret);
}
if(p->ed-ret>1){
add_node(ret, p->ed);
}
auto it = address.find(make_pair(p->st, p->ed));
if(it!=address.end()){
address.erase(it);
delete p;
}
seats.insert(ret);
return ret;
}
return 0;
}
void leave(int p) {
auto it = seats.find(p);
if(it==seats.end()) return;
seats.erase(it);
it = seats.upper_bound(p);
auto high = *it;
it--;
auto low = *it;
auto tmp = address.find(make_pair(low, p));
if(tmp!=address.end()){
tmp->second->valid = 0;
}
tmp = address.find(make_pair(p, high));
if(tmp!=address.end()){
tmp->second->valid = 0;
}
add_node(low, high);
}
set<int> seats;
priority_queue<node*, vector<node*>, cmp> qe;
map<pair<int, int>, node*> address;
int N_;
};
/**
* Your ExamRoom object will be instantiated and called as such:
* ExamRoom obj = new ExamRoom(N);
* int param_1 = obj.seat();
* obj.leave(p);
*/