855. Exam Room

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.

0     1     2     3     4     5     6     7     8     9
seat()   A
seat()   A                        B
seat()   A            C                B
seat()   A            C    。            B
seat()   A     D        C          。     。        B
leave() A     D                             B

需要设计两个api()
seat() -- 找到interval中点最大距离
leave() -- 删除点,并且更新interval
思路: 我们需要动态更新考场座位情况,得出最远的两点距离是多少,并且通过那个距离求的中点。

想成一个interval 的题目,然后用一个data structure,能够返回比较距离。

Solution 1: 
class Interval {
    int start;
    int end;
    int distance;
}
data structure: 
priorityQueue (按照interval distance 中点的长度排列)

seat() -- 从pq里面取出最长的interval, 把这个interval 分成两半,从新放回pq。注意最一开始的情况
当pq里面一个人都没有,把第一个学生放在第零个位置
当pq里面只有一个人,这个人肯定是在第一个位置,那么我们无脑把这个人放到最后一个位置
leave(int id) -- iterate over PQ, 去找到含有这个人的interval, 并且删掉。有三种情况
删除人坐在最右端
删除人坐在最左端
删除人坐在中间,这个情况去要把涉及的两个interval merge起来从新塞回去pq

Time: seat() -- O(logn)  leave -- O(n)
Space: O(n) where n is the number of students

PriorityQueue<Interval> pq;
    int N;

    class Interval {
        int x, y, dist;
        public Interval(int x, int y) {
            this.x = x;
            this.y = y;
            if (x == -1) {
                this.dist = y;
            } else if (y == N) {
                this.dist = N - 1 - x;
            } else {
                this.dist = Math.abs(x - y) / 2;    
            }
        }
    }

    public ExamRoom(int N) {
        this.pq = new PriorityQueue<>((a, b) -> a.dist != b.dist? b.dist - a.dist : a.x - b.x);
        this.N = N;
        pq.add(new Interval(-1, N));
    }

    public int seat() {
        int seat = 0;
        Interval interval = pq.poll();
        if (interval.x == -1) seat = 0;
        else if (interval.y == N) seat = N - 1;
        else seat = (interval.x + interval.y) / 2; 
        
        pq.offer(new Interval(interval.x, seat));
        pq.offer(new Interval(seat, interval.y));
            
        return seat;
    }
    
    public void leave(int p) {
        Interval head = null, tail = null;
        List<Interval> intervals = new ArrayList<>(pq);
        for (Interval interval : intervals) {
            if (interval.x == p) tail = interval;
            if (interval.y == p) head = interval;
            if (head != null && tail != null) break;
        }
        // Delete
        pq.remove(head);
        pq.remove(tail);
        // Merge
        pq.offer(new Interval(head.x, tail.y));
    }



Solution 2:
用treeset sorted的性质来保存学生的座位号。
seat() -- iterate over tree set, 数字相邻两两比较,找出最大符合距离(j - i)/2
    corner case:当教室是空的时候, 加入座位0
    corner case 2: 最右边的位置
leave() -- 删除座位号

Time: seat() -- O(n)  leave -- O(logn)
Space: O(n) where n is ther number of students


class ExamRoom {
    TreeSet<Integer> seats;
    int N;

    public ExamRoom(int N) {
        seats = new TreeSet<>();
        this.N = N;
    }

    public int seat() {
        if (seats.isEmpty()) {
           seats.add(0);
           return 0;
        }
        
        int distance = seats.first() - 0;
        int pos = 0;
        int prev = -1;
        for (int seat: seats) {
            if (prev != -1) {
                int dis = (seat - prev)/2;
                if (dis > distance) {
                    distance = dis;
                    pos = dis + prev;
                }    
            }
            prev = seat;
        }
        if (N - 1 - prev > distance) {
            pos = N - 1;
        }


Solution 3:
seat() log(n)
leave() log(n)
Map 记录下interval 在座位, look up reference
<key = id, value = reference interval>

Follow up:
n个人一起进,同时安排座位,每两个人之间距离最大, 全局思考
=> Minimize max distance to gas station 

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9697635.html
今日推荐