855 考场就座

本文最后更新于:2021年1月10日 上午

在考场里,一排有 N 个座位,分别编号为 0, 1, 2, ..., N-1

当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外,如果考场里没有人,那么学生就坐在 0 号座位上。)

返回 ExamRoom(int N) 类,它有两个公开的函数:其中,函数 ExamRoom.seat() 会返回一个 int (整型数据),代表学生坐的位置;函数 ExamRoom.leave(int p) 代表坐在座位 p 上的学生现在离开了考场。每次调用 ExamRoom.leave(p) 时都保证有学生坐在座位 p 上。

示例:

1
2
3
4
5
6
7
8
9
10
输入:["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]]
输出:[null,0,9,4,2,null,5]
解释:
ExamRoom(10) -> null
seat() -> 0,没有人在考场里,那么学生坐在 0 号座位上。
seat() -> 9,学生最后坐在 9 号座位上。
seat() -> 4,学生最后坐在 4 号座位上。
seat() -> 2,学生最后坐在 2 号座位上。
leave(4) -> null
seat() -> 5,学生最后坐在 5 号座位上。

提示:

  1. 1 <= N <= 10^9
  2. 在所有的测试样例中 ExamRoom.seat()ExamRoom.leave() 最多被调用 10^4 次。
  3. 保证在调用 ExamRoom.leave(p) 时有学生正坐在座位 p 上。

Solution

参考:《算法小抄》5.10 、**@LeetCode官方** 、**@jiangwangjun**

  • 处理动态问题一般要用到有序数据结构,常用的数据结构就是 二叉堆平衡二叉搜索树
  • 二叉堆实现的优先级队列取最值的时间复杂度是 O(logN),但是只能删除最大值。平衡二叉树也可以取最值,也可以修改、删除任意一个值,而且时间复杂度都是 O(logN)。

当我们要调用 seat() 函数时,我们遍历这个有序集合,对于相邻的两个座位 i 和 j,如果选择在这两个座位之间入座,那么最近的距离 d 为 (j - i) / 2,选择的座位为 i + d。除此之外,我们还需要考虑坐在最左侧 0 和最右侧 N - 1 的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class ExamRoom:

def __init__(self, N):
self.N = N
self.students = []

def seat(self):
# Let's determine student, the position of the next
# student to sit down.
if not self.students:
student = 0
else:
# Tenatively, dist is the distance to the closest student,
# which is achieved by sitting in the position 'student'.
# We start by considering the left-most seat.
dist, student = self.students[0], 0
for i, s in enumerate(self.students):
if i:
prev = self.students[i-1]
# For each pair of adjacent students in positions (prev, s),
# d is the distance to the closest student;
# achieved at position prev + d.
d = (s - prev) // 2
if d > dist:
dist, student = d, prev + d

# Considering the right-most seat.
d = self.N - 1 - self.students[-1]
if d > dist:
student = self.N - 1

# Add the student to our sorted list of positions.
bisect.insort(self.students, student)
return student

def leave(self, p):
if p in self.students:
self.students.remove(p)

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!