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:

  1. Input: ["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]]
  2. Output: [null,0,9,4,2,null,5]
  3. Explanation:
  4. ExamRoom(10) -> null
  5. seat() -> 0, no one is in the room, then the student sits at seat number 0.
  6. seat() -> 9, the student sits at the last seat number 9.
  7. seat() -> 4, the student sits at the last seat number 4.
  8. seat() -> 2, the student sits at the last seat number 2.
  9. leave(4) -> null
  10. 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() 中,直接移除离开人的座位位置即可,参见代码如下:

  1. class ExamRoom {
  2. public:
  3. ExamRoom(int N) {
  4. n = N;
  5. }
  6. int seat() {
  7. int start = 0, mx = 0, idx = 0;
  8. for (int i : spots) {
  9. if (start == 0) {
  10. if (mx < i - start) {
  11. mx = i - start;
  12. idx = 0;
  13. }
  14. } else {
  15. if (mx < (i - start + 1) / 2) {
  16. mx = (i - start + 1) / 2;
  17. idx = start + mx - 1;
  18. }
  19. }
  20. start = i + 1;
  21. }
  22. if (start > 0 && mx < n - start) {
  23. mx = n - start;
  24. idx = n - 1;
  25. }
  26. spots.insert(idx);
  27. return idx;
  28. }
  29. void leave(int p) {
  30. spots.erase(p);
  31. }
  32. private:
  33. int n;
  34. set<int> spots;
  35. };

讨论:若这道题还有 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)

[LeetCode] Exam Room 考试房间的更多相关文章

  1. [转]RPA流程自动化-Blueprism认证考试介绍

    本文转自:https://www.cnblogs.com/digod/p/9190186.html RPA流程自动化-Blueprism认证考试介绍 接触RPA有一段时间了,几种RPA相关工具也都试用 ...

  2. RPA流程自动化-Blueprism认证考试介绍

    RPA流程自动化-Blueprism认证考试介绍 接触RPA有一段时间了,几种RPA相关工具也都试用过,BluePrism是RPA工具的一种,今天跟大家分享考Blueprism的一些经验. RPA(R ...

  3. TPO-15 C2 Performance on a biology exam

    TPO-15 C2 Performance on a biology exam 第 1 段 1.Listen to part of a conversation between a Student a ...

  4. Vue回炉重造之搭建考试答卷系统

    本篇章主要讲述系统搭建逻辑,有疑问的可以加微信联系我.考试系统 资源 Vue.js Element UI 第三方数据接口 业务 答题过程中,防止用户中途退出或者其他不可抗力因素阻碍答题,在每次选择都要 ...

  5. weex 小结 -- <list>

    可以包含各种子组件 <refresh style="width:750;padding:30;flex-direction:row;justify-content:center;&qu ...

  6. java经典题目

    /***********Ryear.java begin********************/ import java.util.Scanner;public class Ryear { /** ...

  7. News common vocabulary

    英语新闻常用词汇与短语 经济篇 accumulated deficit 累计赤字 active trade balance 贸易顺差 adverse trade balance 贸易逆差 aid 援助 ...

  8. SGU Volume 1

    SGU 解题报告(持续更新中...Ctrl+A可看题目类型): SGU101.Domino(多米诺骨牌)------------★★★type:图 SGU102.Coprimes(互质的数) SGU1 ...

  9. nodeJS实现简单网页爬虫功能

    前面的话 本文将使用nodeJS实现一个简单的网页爬虫功能 网页源码 使用http.get()方法获取网页源码,以hao123网站的头条页面为例 http://tuijian.hao123.com/h ...

随机推荐

  1. [Kubernetes]深入理解StatefulSet

    前面我写的一系列博客,如果你能够耐心看到这一篇,那你应该对一个概念就不是太陌生了:Deployment. 为什么提这个概念呢,这就要说到Deployment的一个不足了.Deployment不足以覆盖 ...

  2. stylus 实践

    音乐分享: Broken Back - <Halcyon Birds> —————————————————————————————————————————————————————————— ...

  3. ffmpeg推流方式采用TCP协议

    ffmpeg默认推流方式采用UDP方式,若需要使用TCP协议,则需要修改. 1.使用命令时: ffmpeg 跟参数 -rtsp_transport tcp 2.编码时 AVFormatContext ...

  4. [Linux]fcntl函数文件锁概述

    概述 fcntl函数文件锁有几个比较容易忽视的地方: 1.文件锁是真的进程之间而言的,调用进程绝对不会被自己创建的锁锁住,因为F_SETLK和F_SETLKW命令总是替换调用进程现有的锁(若已存在), ...

  5. C++入门篇十三

    常对象: const  Person p1; 不可以调用普通成员函数,除非前面加了函数前面加了const可以调用常函数在对象之前加入const修饰 const Person p1; 常函数:void ...

  6. Lesson 2-3(字符串)

    2.5 字符串 --- 字符串是不可变的. >>> str = "Hello world!" >>> str[-6:-1] = "py ...

  7. 获取clock ticks per second

    #include <sys/syscall.h> #include <stdio.h> #include <unistd.h> int main() { print ...

  8. Mac Segmentation fault: 11

    同样一份代码,在windows10编译运行都没问题.但在mac上运行报Segmentation fault: 11错误. 原因是有指针被定义但是没有分配空间便传入函数,如 double *x; 因为M ...

  9. EF Core 2.2 对多个 DbContext 单个数据库的情况进行迁移的示例

    目录 场景 创建新项目 创建第一个模型 创建第二个模型 使用依赖注入注册上下文 创建数据库 需要注意的情况 场景 在一个项目中,使用了多个 DbContext 且使用同一个数据库的情况 创建新项目 打 ...

  10. Outlook IMAP 修改PST文件存储路径

    IMAP类型的账户修改PST文件位置方法: 对于IMAP类型账户的PST文件,既没有“修改文件夹”的选项,也无法按OFFICE官方操作指南中的操作.因为每次Outlook只要检测到默认路径下的PST文 ...