题目 855.考场就座
难度 中等
在考场里,一排有 N 个座位,分别编号为 0, 1, 2, …, N-1 。
当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外,如果考场里没有人,那么学生就坐在 0 号座位上。)
返回 ExamRoom(int N) 类,它有两个公开的函数:其中,函数 ExamRoom.seat() 会返回一个 int (整型数据),代表学生坐的位置;函数 ExamRoom.leave(int p) 代表坐在座位 p 上的学生现在离开了考场。每次调用 ExamRoom.leave§ 时都保证有学生坐在座位 p 上。
解题思路:
首先看题、分析题意,我们可以明确1个关键点:
1.找到距离最远且编号最小的位置
既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题,
数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
该题的数据结构的作用,保存学生的就座情况
这里有两种方法,分别是顺序的List表和TreeSet。
在这里我们采用TreeSet,变量命名为Students。
因为TreeSet是按键从小到大排序的,而JAVA对TreeSet的封装比较好。
算法:
我们遍历这个有序集合,遍历students,比较每个区间的中点,取得最远且编号最小的点,对于相邻的两个座位 i 和 j,如果选择在这两个座位之间入座
那么最近的距离 d 为 (j - i) / 2,选择的座位为 i + d。除此之外,我们还需要考虑坐在最左侧 0 和最右侧 N - 1 的情况。既然明确了TreeSet作为解决该题的数据结构,我们就可以开始我们的算法分析了。
public class ExamRoom {
int N;
TreeSet<Integer> students;
public ExamRoom(int N) {
this.N=N;
students=new TreeSet<>();
}
//返回距离最远的编号最小空位
public int seat() {
int student = 0;//学生的位置,默认0
if(students.size()>0) {//学生表非空
int dist=students.first();//起始位置为0
// dist 选出距离最近的人最远的位置
Integer prv=null;//区间的左边界
// 不断在区间里面选,这样确保距离最近
for(Integer s:students) {
if(prv!=null)
{
int d=(s-prv)/2;
if(d>dist) { //更新位置和距离
dist=d;
student=prv+d;
}
}
prv=s;
}
if(N-1-students.last()>dist) {//如果N-1位置没有人,则返回N-1
student=N-1;
}
}
students.add(student);
return student;
}
public void leave(int p) {
students.remove(p);//移除P号学生
}
}