【每日一题Day72】LC855考场就座 | 构造数据结构 动态数组+二分查找

考场就座【LC855】

There is an exam room with n seats in a single row labeled from 0 to n - 1.

When a student enters the room, they must sit in the seat that maximizes the distance to the closest person. If there are multiple such seats, they sit in the seat with the lowest number. If no one is in the room, then the student sits at seat number 0.

Design a class that simulates the mentioned exam room.

Implement the ExamRoom class:

  • ExamRoom(int n) Initializes the object of the exam room with the number of the seats n.
  • int seat() Returns the label of the seat at which the next student will set.
  • void leave(int p) Indicates that the student sitting at seat p will leave the room. It is guaranteed that there will be a student sitting at seat p.

复杂度还可以,至少比官方题解好,希望没分析错

  • 思路:

    2022/12/30

    • 由于每次就座时,有三种情况:
      1. 无人就座:坐在0号座位
      2. 1人就座:坐在0号或者n-1号座位
      3. 2人及以上就座:就座座位与相邻两个座位的最小距离最大,因此可以在已就座的座位中找到相邻两个座位距离一半的最大值 d i s dis dis,并记录前一个座位在序号 p r e S e a t preSeat preSeat,新座位序号即为 p r e S e a t + d i s preSeat+dis preSeat+dis
    • 可以使用哈希表记录每个座位是否有人入座,但是当n很大时,每次在搜索距离的时候,不可避免的会搜索到未就座的座位,时间复杂度为O(n);因此我使用动态数组 i s S e a t e d isSeated isSeated记录已经就座的座位序号,并手动保证数组为升序排列(也可以使用TreeSet 做的时候没想到…),然后遍历数组,按照规律就座以及移除座位序号。
  • 实现

    • 初始化:记录位置数量 n n n

    • seat

      1. 情况1: i s S e a t e d isSeated isSeated大小为0,在0号座位就座

      2. 合并情况2和情况3:

        每次就座时在 p r e S e a t preSeat preSeat的后方插入新座位,因此记录 p r e S e a t preSeat preSeat在数组中的下标 p r e I n d e x preIndex preIndex,在其后方插入新座位,保证数组为升序排列

        • 首先在已就座的座位中找到相邻两个座位距离一半的最大值dis,并记录preIndex
        • 然后处理0号座位未就座的情况,此时的距离为isSeated.get(0),若isSeated.get(0)>dis,那么更新dis以及preIndex
        • 再处理n-1号座位未就座的情况,此时的距离为n- 1 - isSeated.get(size - 1),若n- 1 - isSeated.get(size - 1)>dis,那么更新dis以及preIndex
        • 最后将该位置添加至数组中的相应位置

        (也可以在数组中添加哑结点,就不用额外处理了)

    • leave:二分查找座位p的下标,通过remove删除

    class ExamRoom {
        int n;
        // boolean[] isSeated;
        List<Integer> isSeated;
        public ExamRoom(int n) {
            // isSeated = new boolean[n];
            isSeated = new ArrayList<>();
            this.n = n;
        }
    
        public int seat() {
            int size = isSeated.size();
            if (size == 0){
                isSeated.add(0);
                return 0;
            }
            // else if (size == 1){
            //     int temp = isSeated.get(0);
            //     if (isSeated.get(0) < n / 2){
            //         isSeated.add(1, n - 1);
            //         return n - 1;
            //     }else{
            //         isSeated.add(0, 0);
            //         return 0;
            //     }
            // }
            int dis = 0;
            int preIndex = -1;
            // 首位
            if (isSeated.get(0) != 0 ){
                dis = isSeated.get(0);
            }
            for (int i = 0; i < size - 1; i++){
                int temp = (isSeated.get(i + 1) - isSeated.get(i)) / 2;
                if (dis < temp){
                    dis = temp;
                    preIndex = i;
                }
            }
            // 末尾
            if (n - 1 - isSeated.get(size - 1) > dis){
                dis = n - 1 - isSeated.get(size - 1);
                preIndex = size - 1;
            }
            int ans = preIndex == -1 ? 0 : isSeated.get(preIndex) + dis;
            isSeated.add(preIndex + 1, ans);
            return ans;
        }
    
        public void leave(int p) {
            int l = 0, r = isSeated.size() - 1;
            while (l <= r){
                int mid = (l + r) >> 1;
                if (isSeated.get(mid) == p){
                    isSeated.remove(mid);
                    return;
                }else if (isSeated.get(mid) > p){
                    r = mid - 1;
                }else{
                    l = mid + 1;
                }
            }
        }
    }
    
    • 复杂度

      • 时间复杂度:seat函数的时间复杂度为 O ( P ) O(P) O(P),每次都需要遍历整个动态数组,每次add添加元素的时间复杂度为 O ( P ) O(P) O(P)。leave函数的时间复杂度为 O ( P + l o g P ) O(P+logP) O(P+logP),二分查找的时间复杂度为 O ( l o g P ) O(logP) O(logP),remove时间复杂度为 O ( P ) O(P) O(P)
      • 空间复杂度: O ( P ) O(P) O(P)

      image-20221230162317576

  • TreeSet

    class ExamRoom {
        int N;
        TreeSet<Integer> students;
    
        public ExamRoom(int N) {
            this.N = N;
            students = new TreeSet();
        }
    
        public int seat() {
            //Let's determine student, the position of the next
            //student to sit down.
            int student = 0;
            if (students.size() > 0) {
                //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.
                int dist = students.first();
                Integer prev = null;
                for (Integer s: students) {
                    if (prev != null) {
                        //For each pair of adjacent students in positions (prev, s),
                        //d is the distance to the closest student;
                        //achieved at position prev + d.
                        int d = (s - prev) / 2;
                        if (d > dist) {
                            dist = d;
                            student = prev + d;
                        }
                    }
                    prev = s;
                }
    
                //Considering the right-most seat.
                if (N - 1 - students.last() > dist)
                    student = N - 1;
            }
    
            //Add the student to our sorted TreeSet of positions.
            students.add(student);
            return student;
        }
    
        public void leave(int p) {
            students.remove(p);
        }
    }
    
    作者:力扣 (LeetCode)
    链接:https://leetcode.cn/problems/exam-room/solutions/20105/kao-chang-jiu-zuo-by-leetcode/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度

      • 时间复杂度:seat函数的时间复杂度为 O ( P + l o g P ) O(P+logP) O(P+logP),每次都需要遍历整个动态数组,每次add添加元素的时间复杂度为 O ( l o g P ) O(logP) O(logP)。leave函数的时间复杂度为 O ( l o g P ) O(logP) O(logP),remove时间复杂度为 O ( l o g P ) O(logP) O(logP)
      • 空间复杂度: O ( P ) O(P) O(P)

      image-20221230162348876

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值