leetcode力扣刷题系列——【座位预约管理系统】
题目
请你设计一个管理 n 个座位预约的系统,座位编号从 1 到 n 。
请你实现 SeatManager 类:
SeatManager(int n) 初始化一个 SeatManager 对象,它管理从 1 到 n 编号的 n 个座位。所有座位初始都是可预约的。
int reserve() 返回可以预约座位的 最小编号 ,此座位变为不可预约。
void unreserve(int seatNumber) 将给定编号 seatNumber 对应的座位变成可以预约。
示例 1:
输入:
[“SeatManager”, “reserve”, “reserve”, “unreserve”, “reserve”, “reserve”, “reserve”, “reserve”, “unreserve”]
[[5], [], [], [2], [], [], [], [], [5]]
输出:
[null, 1, 2, null, 2, 3, 4, 5, null]
解释:
SeatManager seatManager = new SeatManager(5); // 初始化 SeatManager ,有 5 个座位。
seatManager.reserve(); // 所有座位都可以预约,所以返回最小编号的座位,也就是 1 。
seatManager.reserve(); // 可以预约的座位为 [2,3,4,5] ,返回最小编号的座位,也就是 2 。
seatManager.unreserve(2); // 将座位 2 变为可以预约,现在可预约的座位为 [2,3,4,5] 。
seatManager.reserve(); // 可以预约的座位为 [2,3,4,5] ,返回最小编号的座位,也就是 2 。
seatManager.reserve(); // 可以预约的座位为 [3,4,5] ,返回最小编号的座位,也就是 3 。
seatManager.reserve(); // 可以预约的座位为 [4,5] ,返回最小编号的座位,也就是 4 。
seatManager.reserve(); // 唯一可以预约的是座位 5 ,所以返回 5 。
seatManager.unreserve(5); // 将座位 5 变为可以预约,现在可预约的座位为 [5] 。
提示:
1 <= n <= 105
1 <= seatNumber <= n
每一次对 reserve 的调用,题目保证至少存在一个可以预约的座位。
每一次对 unreserve 的调用,题目保证 seatNumber 在调用函数前都是被预约状态。
对 reserve 和 unreserve 的调用 总共 不超过 105 次。
答案
我的方法
我的方法想的很简单,就是采用列表的形式,可以运行,运行的测试用例也是正确的,但是上传的话会出现超出时间的情况,虽然我运用了for循环,时间复杂度为O(n),但是我认为不是这个导致的,具体为什么,博主太菜了,博主也不知道,有知道的老哥可以分析一下。
class SeatManager(object):
def __init__(self, n):
"""
:type n: int
"""
self.seat = [i for i in range(1,n+1)]
def reserve(self):
"""
:rtype: int
"""
mins = min(self.seat)
self.seat.remove(mins)
return mins
def unreserve(self, seatNumber):
"""
:type seatNumber: int
:rtype: None
"""
self.seat.append(seatNumber)
self.seat.sort()
# Your SeatManager object will be instantiated and called as such:
# obj = SeatManager(n)
# param_1 = obj.reserve()
# obj.unreserve(seatNumber)
官方的方法
官方的方法确实很好,但是有一个问题,在提交过后我发现他并不是最优解,他甚至是排在倒数的位置的,那么我们先看官方的方法吧,最后我们在看看其他大神最优的解法是如何做到的。
提示 1
考虑 reserve 与 unreserve 方法对应的需求。什么样的数据结构能够在较好的时间复杂度下支持这些操作?
思路与算法
根据 提示 1,假设我们使用数据结构 available 来维护所有可以预约的座位,我们需要分析 reserve 与 unreserve 的具体需求:
- 对于 reserve 方法,我们需要弹出并返回 available 中的最小元素;
- 对于 unreserve 方法,我们需要将 seatNumber 添加至 available 中。
- 因此我们可以使用二叉堆实现的优先队列作为 available。对于一个最小堆,可以在 O(logn)的时间复杂度内完成单次「添加元素」与「弹出最小值」的操作。
- 需要注意的是,Python 的二叉堆默认为最小堆,但 C++ 的二叉堆默认为最大堆。
from heapq import heappush, heappop
class SeatManager:
def __init__(self, n: int):
self.available = list(range(1, n + 1))
def reserve(self) -> int:
return heappop(self.available)
def unreserve(self, seatNumber: int) -> None:
heappush(self.available, seatNumber)
作者:力扣官方题解
链接:这是连接哦
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这边文章并没有写完,为什么没有写完呢?因为博主还在看官方给的解题思路,对于python本身博主就没有很好地学习,很多时候我要看很久才知道这个怎么做,不过我保证今天一定把这个完成!
————————————————————————————————————————————
我忙完回来了,兄弟们,官方给的代码我也看懂了。
首先说为什么我的代码会超时呢? 首先并不是我运用了for循环导致的时间复杂度为o(n),而是列表的插入和删除函数本身时间复杂度就是O(n)!!!!
然后为什么当数据足够多的时候官方的代码就能运行呢? 这是因为官方采用的是堆排序,而python中的heapq是最小堆。堆排序是完全二叉树,他的时间复杂度是O(logn)。
当我们假设n=1024时,前者的量级大约是 1024,而后者的时间复杂度,假设我们以2为底的话是他的量级为log2(1024)=10。是不是减少了很多的时间呢?
简单放个图让大家看一下什么是堆。
最后! 最后一点! 为什么官方给的代码也排到了倒数的位置上呢?
说实话,我也不知道因为什么,我也尝试了其他人的代码,最后的结果都在这个位置,本来我以为是语言的问题,但是当我用C++提交了一次之后,发现他排名好像也不看这个,不同的语言排名是不一样的,但是我又不知道其他大哥怎么写的,所以如果有大佬能优化,让他更快的请发表出来,让我们也都学习一下。