考场就座
难度:
标签:
题目描述
代码结果
运行时间: 64 ms, 内存: 0.0 MB
/*
思路:
1. 使用一个 TreeSet 记录已经被占据的座位,以保持有序。
2. 每次调用 seat() 时,找到能够使离他最近的人之间的距离最大化的座位。
3. 使用 leave(p) 函数将座位 p 标记为空。
*/
import java.util.TreeSet;
public class ExamRoom {
private int N;
private TreeSet<Integer> seats;
public ExamRoom(int N) {
this.N = N;
this.seats = new TreeSet<>();
}
public int seat() {
if (seats.isEmpty()) {
seats.add(0);
return 0;
}
int maxDist = seats.first();
int seat = 0;
Integer prev = null;
for (int s : seats) {
if (prev != null) {
int dist = (s - prev) / 2;
if (dist > maxDist) {
maxDist = dist;
seat = prev + dist;
}
}
prev = s;
}
if (N - 1 - seats.last() > maxDist) {
seat = N - 1;
}
seats.add(seat);
return seat;
}
public void leave(int p) {
seats.remove(p);
}
}
解释
方法:
这个题解使用了优先队列(最大堆)来快速找到最优的座位。首先,每个区间(即连续的空座位)被标记为一个三元组 [-priority, first, last],其中 priority 是该区间的优先级,first 和 last 分别是区间的起始和结束座位。如果区间是开头或结尾的座位,优先级就是区间长度;否则,优先级是区间长度除以二的商。这样设计是为了优先坐在最中间的位置,以最大化与最近的人的距离。当座位被选取时,相关区间会被拆分并重新加入堆中,如果座位 p 被释放,相邻的空座位区间会合并并更新。
时间复杂度:
O(log n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在初始化ExamRoom时,整个座位区间被设定为从0到N-1?这是否意味着开始时考场是完全空的?
▷🦆
在put_segment函数中,为什么边界区间的优先级是整个区间长度,而非边界区间的优先级是区间长度除以二?这样的处理对于找到最优座位的影响是什么?
▷🦆
在seat函数中,如何确保从堆中弹出的区间是有效的?如果堆中的区间因为之前的leave操作而变得无效,这种情况是如何处理的?
▷相关问题
到最近的人的最大距离
给你一个数组 seats
表示一排座位,其中 seats[i] = 1
代表有人坐在第 i
个座位上,seats[i] = 0
代表座位 i
上是空的(下标从 0 开始)。
至少有一个空座位,且至少有一人已经坐在座位上。
亚历克斯希望坐在一个能够使他与离他最近的人之间的距离达到最大化的座位上。
返回他到离他最近的人的最大距离。
示例 1:

输入:seats = [1,0,0,0,1,0,1] 输出:2 解释: 如果亚历克斯坐在第二个空位(seats[2])上,他到离他最近的人的距离为 2 。 如果亚历克斯坐在其它任何一个空位上,他到离他最近的人的距离为 1 。 因此,他到离他最近的人的最大距离是 2 。
示例 2:
输入:seats = [1,0,0,0] 输出:3 解释: 如果亚历克斯坐在最后一个座位上,他离最近的人有 3 个座位远。 这是可能的最大距离,所以答案是 3 。
示例 3:
输入:seats = [0,1] 输出:1
提示:
2 <= seats.length <= 2 * 104
seats[i]
为0
或1
- 至少有一个 空座位
- 至少有一个 座位上有人