[LeetCode] 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. 1 <= N <= 10^9
  2. ExamRoom.seat() and ExamRoom.leave() will be called at most 10^4 times across all test cases.
  3. Calls to ExamRoom.leave(p) are guaranteed to have a student currently sitting in seat number p.

這道題是之前那道 [Maximize Distance to Closest Person](https://www.cnblogs.com/grandyang/p/10503789.html) 的拓展,說是有個考場,每個考生入座的時候都要盡可能的跟左右兩邊的人距離保持最大,當最大距離相同的時候,考生坐在座位編號較小的那個位置。對於牆的處理跟之前那道是一樣的,能靠牆就盡量靠牆,這樣肯定離別人最遠。其實在之前那道題 [Maximize Distance to Closest Person](https://www.cnblogs.com/grandyang/p/10503789.html) 最后的討論部分博主就預言了這道題,當時博主還沒有看這道題,果然是要我們返回座位的具體位置。

博主最先想的方法是用一個大小為N的數組來表示所有的座位,初始化為0,表示沒有一個人,若有人入座了,則將該位置變為1,離開則變為0,那么對於 leave() 函數就十分簡單了,直接將對應位置改為0即可。重點就是 seat() 函數了,這個可以借鑒之前那道 Maximize Distance to Closest Person 的思路,采用雙指針來做,主要就是找連續的0進行處理,還是要分 start 是否為0的情況,因為空位從牆的位置開始,跟空位在兩人之間的處理情況是不同的,若空位從牆開始,肯定是坐牆邊,而若是在兩人之間,則需要坐在最中間,還要記得更新 start 為下一個空座位。最后在處理末尾空位連到牆的時候,跟之前稍有些不同,因為題目要求當最大距離相同的時候,需要選擇座位號小的位置,而當此時 start 為0的時候,說明所有的位置都是空的,那么我們不需要再更新 idx 了,就用其初始值0,表示就坐在第一個位置,是符合題意的。最后別忘了將 idx 位置賦值為1,表示有人坐了。

看到這里,你一定以為大功告成了吧,but,OJ總是不斷給人驚喜,Time Limit Exceeded,貌似不讓我們這么輕易過關啊。那么只能進行優化了,首先分析上面的思路哪塊比較耗時,其實就是遍歷,當有大量的空座位的時候,中間的0還得一個個遍歷,不是很高效,那么比較直接的改進方法就是去掉那些0,我們只保存有人坐的位置,即所有1的位置。這樣省去了遍歷0的時間,大大提高了效率,此時我們就可以使用 TreeSet 來保存1的位置,其余部分並不怎么需要改變,在確定了座位 idx 時,將其加入 TreeSet 中。在 leave() 中,直接移除離開人的座位位置即可,參見代碼如下:


class ExamRoom {
public:
    ExamRoom(int N) {
        n = N;
    }
    
    int seat() {
        int start = 0, mx = 0, idx = 0;
        for (int i : spots) {
            if (start == 0) {
                if (mx < i - start) {
                    mx = i - start;
                    idx = 0;
                }
            } else {
                if (mx < (i - start + 1) / 2) {
                    mx = (i - start + 1) / 2;
                    idx = start + mx - 1;
                }
            }
            start = i + 1;
        }
        if (start > 0 && mx < n - start) {
            mx = n - start;
            idx = n - 1;
        }
        spots.insert(idx);
        return idx;
    }
    
    void leave(int p) {
        spots.erase(p);
    }

private:
    int n;
    set<int> spots;
};

討論:若這道題還有 follow up 的話,那么博主能想到的就是變成二維的數組,這樣才更像一個真正的考場啊,畢竟大多數考場都不是只有一排座位的。變成了二維的話,那么周圍四面八方的人的距離都要考慮呢,想想覺得還挺難的,大家有什么想法的話,歡迎留言討論哈~
Github 同步地址:

https://github.com/grandyang/leetcode/issues/855


類似題目:

Maximize Distance to Closest Person


參考資料:

https://leetcode.com/problems/exam-room/

https://leetcode.com/problems/exam-room/discuss/139862/C%2B%2BJavaPython-Straight-Forward

https://leetcode.com/problems/exam-room/discuss/148595/Java-PriorityQueue-with-customized-object.-seat%3A-O(logn)-leave-O(n)-with-explanation


[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM