Leetcode考场就坐

在这里插入图片描述

我的解法:
1.考虑极端情况,无人就座,只有1人就座且(坐在左边,中间,最右边),只剩下最左边和最右边的座位等等
2.想的是查找最大的间隔,如果间隔两端都有人那么就坐中间,如果间隔左边没人坐左边,左边有人右边无人坐右边
3.如果间隔大于1/2总长度就可以跳出了,后面的间隔不会更大了
在这里插入图片描述

class ExamRoom:

    def __init__(self, n: int):
        self.seat_list=[]
        self.seat_set=set()
        self.left=0
        self.right=0
        self.n=n

    def seat(self) -> int:
        n=self.n
        if self.seat_list==[]:
           self.seat_list.append(0)
           self.seat_set.add(0)
           return 0
        if len(self.seat_set)>=n-2 and 0 not in self.seat_set:
           self.seat_list.insert(0,0)
           self.seat_set.add(0)
           return 0 
        last=-1
        max_gap=n-1-self.seat_list[-1]-1
        if max_gap<0:
            max_gap=0
        left=-1
        right=n
        half_gap=n//2 
        insert_loc=0
        for student in range(0,len(self.seat_list)):
            gap=self.seat_list[student]-last

            if gap//2>max_gap//2: 
               max_gap=gap
               left=last
               right=self.seat_list[student]
               insert_loc=student

            if max_gap>half_gap:
               break 
            last=self.seat_list[student]
        if left in self.seat_set and right in self.seat_set:
            new_seat=(left+right)//2
            self.seat_list.insert(insert_loc,new_seat)
            self.seat_set.add(new_seat)
            return new_seat
        if n-1 not in self.seat_set:
           self.seat_list.append(n-1)
           self.seat_set.add(n-1)
           return n-1   
        self.seat_list.insert(0,0)
        self.seat_set.add(0)
        return 0    
        

    def leave(self, p: int) -> None:
        self.seat_list.remove(p)
        self.seat_set.remove(p)

标准解法:

class ExamRoom:

    def __init__(self, n: int):        
        self.heap_info = []        
        self.last = n - 1
        heappush(self.heap_info, [-self.last, -1, self.last + 1])       
        
    def seat(self) -> int:
        gap, left, right = heappop(self.heap_info)
        if left < 0:
            if right > self.last:
                heappush(self.heap_info, [-self.last, 0, right])
            elif right > 1:
                heappush(self.heap_info, [-(right >> 1), 0, right])   
            return 0
        elif right > self.last:
            if gap < -1:
                heappush(self.heap_info, [-(-gap >> 1), left, self.last])   
            return self.last
        else:
            seat_idx = left - gap
            if gap < -1:
                heappush(self.heap_info, [-(-gap >> 1), left, seat_idx])   
                heappush(self.heap_info, [-((right - seat_idx) >> 1), seat_idx, right])
            elif left + 3 == right:
                heappush(self.heap_info, [-1, seat_idx, right])   
            return seat_idx

    def leave(self, p: int) -> None:
        if p == 0:
            right = 1
            for i in range(len(self.heap_info)):
                if self.heap_info[i][1] == 0:
                    _, _, right = self.heap_info.pop(i)
                    break
            heappush(self.heap_info, [-right, -1, right])                                      
        elif p == self.last:
            left = p - 1
            for i in range(len(self.heap_info)):
                if self.heap_info[i][2] == self.last:
                    _, left, _ = self.heap_info.pop(i)
                    break
            heappush(self.heap_info, [left - self.last, left, self.last + 1])                      
        else:
            cnt = 0
            left, right = p - 1, p + 1
            for i in range(len(self.heap_info) - 1, -1, -1):
                if self.heap_info[i][1] == p:
                    _, _, right = self.heap_info.pop(i)
                    if cnt == 1:
                        break
                    cnt = 1                
                elif self.heap_info[i][2] == p:
                    _, left, _ = self.heap_info.pop(i)
                    if cnt == 1:
                        break
                    cnt = 1   
                
            if left < 0:
                gap = right
            elif right > self.last:
                gap = self.last - left
            else:
                gap = (right - left) >> 1
            heappush(self.heap_info, [-gap, left, right])                    
                    
        return None

python的heappush和heappop:
1.heappush(heap,item)建立大、小根堆
heapq.heappush()是往堆中添加新值,此时自动建立了小根堆
不能直接建立大跟堆,所以每次push时给元素加一个负号(即取相反数),此时最小值变最大值,反之亦然,那么实际上的最大值就可以处于堆顶了,返回时再取负即可。
2.heapq.heappop()从堆中弹出并返回最小的值
普通list(即并没有进行heapify等操作的list),对他进行heappop操作并不会弹出list中最小的值,而是弹出第一个值。
对于小跟堆,会依次弹出最小的值。

x>>1相当于快速的x//2

原文链接:https://blog.csdn.net/qq_38022469/article/details/123851001

其他解答:
区间的左右两边用有序列表存储,元素是一个元组,排序的key是计算距离的负数,这样可以确保大的值排在前面,第二个排序依据是x[0]就是区间的左边位置,确保先坐序号小的
这样seat的时候就相当于删除了原来的区间,把其分割为两个新的区间。
两个字典存放的是当前学生左右两边的学生,方便删除的时候合并区间,这个比较好懂一些

from sortedcontainers import SortedList


class ExamRoom:

    def __init__(self, n: int):
        def dist(x):
            l, r = x
            return r - l - 1 if l == -1 or r == n else (r - l) >> 1

        self.n = n
        self.ts = SortedList(key=lambda x: (-dist(x), x[0]))
        self.left = {}
        self.right = {}
        self.add((-1, n))

    def seat(self) -> int:
        s = self.ts[0]
        p = (s[0] + s[1]) >> 1
        if s[0] == -1:
            p = 0
        elif s[1] == self.n:
            p = self.n - 1
        self.delete(s)
        self.add((s[0], p))
        self.add((p, s[1]))
        return p

    def leave(self, p: int) -> None:
        l, r = self.left[p], self.right[p]
        self.delete((l, p))
        self.delete((p, r))
        self.add((l, r))

    def add(self, s):
        self.ts.add(s)
        self.left[s[1]] = s[0]
        self.right[s[0]] = s[1]

    def delete(self, s):
        self.ts.remove(s)
        self.left.pop(s[1])
        self.right.pop(s[0])

作者:lcbin
链接:https://leetcode.cn/problems/exam-room/solution/by-lcbin-tstp/
来源:力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值