LeetCode每日一题(855. Exam Room)

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值