算法初探LeetCode-考场就座

219 阅读2分钟

LeetCode855:考场就座

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

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

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

示例:

输入: ["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<=1091 <= N <= 10^9
  2. 在所有的测试样例中 ExamRoom.seat() 和 ExamRoom.leave() 最多被调用 10410^4 次。
  3. 保证在调用 ExamRoom.leave(p) 时有学生正坐在座位 p 上。

思路分析

  • set存的是位置,不是坐标,所以leave()的时候可以直接删除位置
  • 有有序集合存:存进去的时候是乱的,但是遍历的时候是有序的
  • 怎么遍历区间:
  1. left从set第一个元素开始,right遍历set每个取值
  2. distance初始为距离0位置的距离set.first() – 0 = set.frist()
  3. index为要选的位置,初始值为0
  4. 区间距离为(right - left) / 2,中点坐标(left + right) / 2
  5. 切换下一个区间令left = right即可

算法代码

TreeSet < Integer > set; // 保存已经选了的座位
int n; // 座位总数

public ExamRoom(int n) {
    this.n = n;
    this.set = new TreeSet < > ();
}

public int seat() {
    if (set.isEmpty()) { // 集合为空,选位置0
        set.add(0);
        return 0;
    }
    // 遍历区间,选出距离最大的一个中电
    int left = set.first();
    int distance = set.first(); // 初始选择最左的长度
    int index = 0; // 要选的位置
    for (int right: set) {
        if (distance < (right - left) / 2) {
            distance = (right - left) / 2;
            index = (right + left) / 2;
        }
        left = right;
    }
    // 判断如果把位置放置在最后一位
    int d = n - 1 - set.last();
    if (distance < d) {
        distance = d;
        index = n - 1;
    }
    set.add(index);
    return index;
}

public void leave(int p) {
    set.remove(p);
}

结果详情

Snipaste_2023-04-13_22-26-52.png

算法复杂度

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n2)O(n^2)

掘金(JUEJIN)一起进步,一起成长!