LeetCode破解之座位分配

269 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

题目描述

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

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

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

示例 1:

输入:["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 号座位上。

HashMap+TreeSet

思路分析:很明显可以发现如果线段接近相等,按照线段start值降序排序,确保有多个这样的座位,他会坐在编号最小的座位上。那我们按照距离升序排序,在有序集合中先放一个虚拟线段,一定注意处理虚拟线段的距离。计算中点和端点之间的长度,确保线段接近相等的特殊case。从有序集合中取出最长的线段:

  • 情况一,最左边没人,坐最左
  • 情况二,最右边没人,坐最右
  • 情况三,不是边界,坐中间

对于有了新的端点,更新HashMap和TreeSet。记得删除之前的线段,加入新的线段。

class ExamRoom {
    static TreeSet<Integer> sets;
    static int ilen;
    public ExamRoom(int N) {
        sets = new TreeSet<Integer>();
        ilen = N;
    }
    
    public int seat() {

        if (sets.size() == 0) {
            sets.add(0);
            return 0;
        }
        List<Integer> ilist = new ArrayList<Integer>(sets);
        if (ilist.size() == 1) {
            if (ilist.get(0) == 0) {
                sets.add(ilen - 1);
                return ilen - 1;
            } else if (ilist.get(0) == ilen - 1) {
                sets.add(0);
                return 0;
            } else if (2 * ilist.get(0) >= ilen) {
                sets.add(0);
                return 0;
            } else {
                sets.add(ilen - 1);
                return ilen - 1;
            }
        }
        int imax = 2*ilist.get(0) - 0;
        int iindex = 0;
        for (int i = 1; i < ilist.size(); i++) {
            int idev = ilist.get(i) - ilist.get(i - 1);
            if (imax % 2 == 0 & idev > imax + 1) {
                imax = ilist.get(i) - ilist.get(i - 1);
                iindex = i;
            }
            if (imax % 2 == 1 & idev > imax) {
                imax = ilist.get(i) - ilist.get(i - 1);
                iindex = i;
            }
        }
        if (ilen - 1 - ilist.get(ilist.size() - 1) > imax) {
            sets.add(ilen - 1);
            return ilen - 1;
        }
        if (iindex == 0) {
            sets.add(0);
            return 0;
        }
        sets.add((ilist.get(iindex) + ilist.get(iindex - 1)) / 2);
        return ((ilist.get(iindex) + ilist.get(iindex - 1)) / 2);
    
    }
    
    public void leave(int p) {
        sets.remove(p);
    }
}

最后

题目有几个注意点:1、set为空直接占据0;2、set大小为1,就看唯一的元素离哪边更远;3、set大小大于1,那么就查找其中最远的距离,之后还要验证0和N-1不在集合里面的情况。如果想采用暴力破解,获取比对下标最小值. 那就只能吃TE。