There is an exam room with n seats in a single row labeled from 0 to 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. If no one is in the room, then the student sits at seat number 0.
Design a class that simulates the mentioned exam room.
Implement the ExamRoom class:
ExamRoom(int n) Initializes the object of the exam room with the number of the seats n.
int seat() Returns the label of the seat at which the next student will set.
void leave(int p) Indicates that the student sitting at seat p will leave the room. It is guaranteed that there will be a student sitting at seat p.
Example 1:
Input
[“ExamRoom”, “seat”, “seat”, “seat”, “seat”, “leave”, “seat”]
[[10], [], [], [], [], [4], []]
Output
[null, 0, 9, 4, 2, null, 5]
Explanation
ExamRoom examRoom = new ExamRoom(10);
examRoom.seat(); // return 0, no one is in the room, then the student sits at seat number 0.
examRoom.seat(); // return 9, the student sits at the last seat number 9.
examRoom.seat(); // return 4, the student sits at the last seat number 4.
examRoom.seat(); // return 2, the student sits at the last seat number 2.
examRoom.leave(4);
examRoom.seat(); // return 5, the student sits at the last seat number 5.
Constraints:
1 <= n <= 109
It is guaranteed that there is a student sitting at seat p.
At most 104 calls will be made to seat and leave.
开始一直想把seat()和leave()的复杂度都降到O(logn),seat()好说,priority queue就可以达到,但是leave()想了半天也没想到合适的办法,最后放弃了,去看讨论区,结果人家说硬刚就好,O(n)没问题。
本质上来说,这就是个范围的合并和分割的问题,捎带考虑上头尾两个元素的特殊情况就好了。
use std::cmp::{Ord, Ordering, PartialOrd};
#[derive(Eq, PartialEq, Debug)]
struct Range(i32, i32);
impl Range {
fn max_dist(&self) -> i32 {
if self.0 < 0 || self.1 < 0 {
self.1.abs() - self.0.abs()
} else {
(self.1.abs() - self.0.abs()) / 2
}
}
}
impl PartialOrd for Range {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Range {
fn cmp(&self, other: &Self) -> Ordering {
let dist1 = self.max_dist();
let dist2 = other.max_dist();
if dist1 < dist2 {
return Ordering::Less;
} else if dist1 > dist2 {
return Ordering::Greater;
} else {
if self.0.abs() < other.0.abs() {
return Ordering::Greater;
} else {
return Ordering::Less;
}
}
}
}
struct ExamRoom {
ranges: Vec<Range>,
}
impl ExamRoom {
fn new(n: i32) -> Self {
Self {
ranges: vec![Range(-1, -n)],
}
}
fn seat(&mut self) -> i32 {
let max_idx = self
.ranges
.iter()
.enumerate()
.max_by_key(|(_, r)| *r)
.map(|(i, _)| i)
.unwrap();
let Range(s, e) = self.ranges[max_idx];
if s < 0 {
self.ranges[max_idx].0 = -s;
return -s - 1;
}
if e < 0 {
self.ranges[max_idx].1 = -e;
return -e - 1;
}
let mid = s + (e - s) / 2;
self.ranges[max_idx].1 = mid;
self.ranges.insert(max_idx + 1, Range(mid, e));
mid - 1
}
fn leave(&mut self, p: i32) {
if p == 0 {
self.ranges[0].0 = -1;
return;
}
if p == self.ranges.last().unwrap().1 - 1 {
self.ranges.last_mut().unwrap().1 = -self.ranges.last_mut().unwrap().1;
return;
}
let pos = self
.ranges
.iter()
.position(|&Range(s, e)| s <= p + 1 && e >= p + 1)
.unwrap();
self.ranges[pos].1 = self.ranges[pos + 1].1;
self.ranges.remove(pos + 1);
}
}