Medium
题目描述
设计一个管理 n 个座位预约状态的系统,座位编号从 1 到 n。
实现 SeatManager 类:
SeatManager(int n)初始化一个SeatManager对象,它将管理从 1 到 n 编号的 n 个座位。所有座位最初都是可用的。int reserve()获取并预约编号最小的未预约座位,返回其编号。void unreserve(int 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); // 初始化一个能管理5个座位的SeatManager。
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 <= 10^51 <= seatNumber <= n- 每次调用
reserve时,都保证至少有一个座位未被预约。 - 每次调用
unreserve时,都保证seatNumber已被预约。 - 总共最多调用
reserve和unreserve方法10^5次。
解题思路
这道题要求我们设计一个座位预约管理系统,核心是要快速找到编号最小的可用座位,同时能够高效地释放座位。
思路分析:
最直观的想法是使用最小堆(优先队列)来存储所有可用的座位号。这样可以保证每次 reserve() 操作都能在 O(log n) 时间内获取到最小的座位号,unreserve() 操作也能在 O(log n) 时间内将座位重新加入可用列表。
具体实现:
- 初始化:将所有座位号(1到n)加入最小堆
- 预约座位:从堆顶取出最小的座位号并返回
- 释放座位:将释放的座位号重新加入堆中
优化思路:
初始时可以不将所有座位都加入堆中,而是维护一个 nextAvailable 指针,只有当有座位被释放时才加入堆。这样可以节省初始化时间和空间。
推荐解法: 使用最小堆存储可用座位,配合 nextAvailable 指针优化,既保证了效率又节省了空间。
代码实现
class SeatManager {
private:
priority_queue<int, vector<int>, greater<int>> availableSeats;
int nextAvailable;
public:
SeatManager(int n) {
nextAvailable = 1;
}
int reserve() {
if (!availableSeats.empty()) {
int seat = availableSeats.top();
availableSeats.pop();
return seat;
}
return nextAvailable++;
}
void unreserve(int seatNumber) {
availableSeats.push(seatNumber);
}
};
import heapq
class SeatManager:
def __init__(self, n: int):
self.available_seats = []
self.next_available = 1
def reserve(self) -> int:
if self.available_seats:
return heapq.heappop(self.available_seats)
seat = self.next_available
self.next_available += 1
return seat
def unreserve(self, seatNumber: int) -> None:
heapq.heappush(self.available_seats, seatNumber)
public class SeatManager {
private PriorityQueue<int, int> availableSeats;
private int nextAvailable;
public SeatManager(int n) {
availableSeats = new PriorityQueue<int, int>();
nextAvailable = 1;
}
public int Reserve() {
if (availableSeats.Count > 0) {
return availableSeats.Dequeue();
}
return nextAvailable++;
}
public void Unreserve(int seatNumber) {
availableSeats.Enqueue(seatNumber, seatNumber);
}
}
var SeatManager = function(n) {
this.availableSeats = [];
this.nextAvailable = 1;
};
SeatManager.prototype.reserve = function() {
if (this.availableSeats.length > 0) {
this.availableSeats.sort((a, b) => a - b);
return this.availableSeats.shift();
}
return this.nextAvailable++;
};
SeatManager.prototype.unreserve = function(seatNumber) {
this.availableSeats.push(seatNumber);
};
复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 初始化 | O(1) | O(1) |
| reserve() | O(log k) | O(k) |
| unreserve() | O(log k) | O(k) |
其中 k 是已释放但尚未重新预约的座位数量。在最坏情况下,k 可能接近 n。
相关题目
. Design Phone Directory (Medium)
. Design a Number Container System (Medium)