/**
* 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() and ExamRoom.leave() will be called at most 10^4 times across all test cases.
* Calls to ExamRoom.leave(p) are guaranteed to have a student currently sitting in seat number p.
*/
public class ExamRoom855 {
class ExamRoom {
private PriorityQueue pq;
private Map lefts;
private Map rights;
private int N;
public ExamRoom(int N) {
this.pq = new PriorityQueue(1, new Comparator() {
@Override
public int compare(Range r1, Range r2) {
int rangeDiff = Integer.compare(dis(r2), dis(r1));
if (rangeDiff != 0) return rangeDiff;
return Integer.compare(r1.left, r2.left);
}
});
this.lefts = new HashMap<>();
this.rights = new HashMap<>();
this.N = N;
Range first = new Range(-1, N);
this.pq.add(first);
this.lefts.put(first.left, first);
this.rights.put(first.right, first);
}
public int seat() {
if (this.pq.isEmpty()) return -1;
Range curr = this.pq.poll();
this.lefts.remove(curr.left);
this.rights.remove(curr.right);
int pos = sitPos(curr);
Range l = new Range(curr.left, pos);
this.lefts.put(l.left, l);
this.rights.put(l.right, l);
if (curr.left + 1 < pos) {
this.pq.add(l);
}
Range r = new Range(pos, curr.right);
this.lefts.put(r.left, r);
this.rights.put(r.right, r);
if (pos + 1 < curr.right) {
this.pq.add(r);
}
return pos;
}
public void leave(int p) {
Range r = this.lefts.get(p);
Range l = this.rights.get(p);
this.pq.remove(r);
this.pq.remove(l);
Range merged = new Range(l.left, r.right);
this.pq.add(merged);
this.lefts.put(merged.left, merged);
this.rights.put(merged.right, merged);
}
private int sitPos(Range r) {
return sitPos(r.left, r.right);
}
private int sitPos(int left, int right) {
if (left + 1 >= right) return -1;
if (left < 0) return 0;
if (right >= this.N) return this.N - 1;
return (right - left) / 2 + left;
}
private int dis(Range r) {
return dis(r.left, r.right);
}
private int dis(int left, int right) {
if (left < 0) return right;
if (right >= this.N) return this.N - 1 - left;
return (right - left) / 2;
}
}
class Range {
int left;
int right;
Range (int l, int r) {
this.left = l;
this.right = r;
}
}
/**
* Your ExamRoom object will be instantiated and called as such:
* ExamRoom obj = new ExamRoom(N);
* int param_1 = obj.seat();
* obj.leave(p);
*/
}