LeetCode 题解工作台
我的日程安排表 III
当 k 个日程存在一些非空交集时(即, k 个日程包含了一些相同时间),就会产生 k 次预订。 给你一些日程安排 [startTime, endTime) ,请你在每个日程安排添加后,返回一个整数 k ,表示所有先前日程安排会产生的最大 k 次预订。 实现一个 MyCalendarThree 类来存…
5
题型
5
代码语言
3
相关题
当前训练重点
困难 · 二分·搜索·答案·空间
答案摘要
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 。更新某个元素的值,只需要更新 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用懒标记保证效率。 - 线段树的每个节点代表一个区间;
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 二分·搜索·答案·空间 题型思路
题目描述
当 k 个日程存在一些非空交集时(即, k 个日程包含了一些相同时间),就会产生 k 次预订。
给你一些日程安排 [startTime, endTime) ,请你在每个日程安排添加后,返回一个整数 k ,表示所有先前日程安排会产生的最大 k 次预订。
实现一个 MyCalendarThree 类来存放你的日程安排,你可以一直添加新的日程安排。
MyCalendarThree()初始化对象。int book(int startTime, int endTime)返回一个整数k,表示日历中存在的k次预订的最大值。
示例:
输入: ["MyCalendarThree", "book", "book", "book", "book", "book", "book"] [[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]] 输出: [null, 1, 1, 2, 3, 3, 3] 解释: MyCalendarThree myCalendarThree = new MyCalendarThree(); myCalendarThree.book(10, 20); // 返回 1 ,第一个日程安排可以预订并且不存在相交,所以最大 k 次预订是 1 次预订。 myCalendarThree.book(50, 60); // 返回 1 ,第二个日程安排可以预订并且不存在相交,所以最大 k 次预订是 1 次预订。 myCalendarThree.book(10, 40); // 返回 2 ,第三个日程安排 [10, 40) 与第一个日程安排相交,所以最大 k 次预订是 2 次预订。 myCalendarThree.book(5, 15); // 返回 3 ,剩下的日程安排的最大 k 次预订是 3 次预订。 myCalendarThree.book(5, 10); // 返回 3 myCalendarThree.book(25, 55); // 返回 3
提示:
0 <= startTime < endTime <= 109- 每个测试用例,调用
book函数最多不超过400次
解题思路
方法一:线段树
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 。更新某个元素的值,只需要更新 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用懒标记保证效率。
- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 ;
- 线段树的每个叶子节点代表一个长度为 的元区间 ;
- 对于每个内部节点 ,它的左儿子是 ,右儿子是 , 其中 (即向下取整)。
对于本题,线段树节点维护的信息有:
- 区间范围内被预定的次数的最大值
- 懒标记
由于时间范围为 ,非常大,因此我们采用动态开点。
时间复杂度 ,空间复杂度 ,其中 表示日程安排的数量。
class Node:
def __init__(self, l, r):
self.left = None
self.right = None
self.l = l
self.r = r
self.mid = (l + r) >> 1
self.v = 0
self.add = 0
class SegmentTree:
def __init__(self):
self.root = Node(1, int(1e9 + 1))
def modify(self, l: int, r: int, v: int, node: Node = None):
if l > r:
return
if node is None:
node = self.root
if node.l >= l and node.r <= r:
node.v += v
node.add += v
return
self.pushdown(node)
if l <= node.mid:
self.modify(l, r, v, node.left)
if r > node.mid:
self.modify(l, r, v, node.right)
self.pushup(node)
def query(self, l: int, r: int, node: Node = None) -> int:
if l > r:
return 0
if node is None:
node = self.root
if node.l >= l and node.r <= r:
return node.v
self.pushdown(node)
v = 0
if l <= node.mid:
v = max(v, self.query(l, r, node.left))
if r > node.mid:
v = max(v, self.query(l, r, node.right))
return v
def pushup(self, node: Node):
node.v = max(node.left.v, node.right.v)
def pushdown(self, node: Node):
if node.left is None:
node.left = Node(node.l, node.mid)
if node.right is None:
node.right = Node(node.mid + 1, node.r)
if node.add:
node.left.v += node.add
node.right.v += node.add
node.left.add += node.add
node.right.add += node.add
node.add = 0
class MyCalendarThree:
def __init__(self):
self.tree = SegmentTree()
def book(self, start: int, end: int) -> int:
self.tree.modify(start + 1, end, 1)
return self.tree.query(1, int(1e9 + 1))
# Your MyCalendarThree object will be instantiated and called as such:
# obj = MyCalendarThree()
# param_1 = obj.book(start,end)
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity depends on the approach: sweep line with sorting is O(N log N), segment tree can achieve O(N log M) where M is the number of distinct time points. Space complexity is O(N) for events storage or O(M) for segment tree nodes. |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Asks about handling large time ranges efficiently.
- question_mark
Mentions potential overlapping edge cases like fully nested intervals.
- question_mark
Questions the trade-off between direct simulation and segment tree efficiency.
常见陷阱
外企场景- error
Neglecting the half-open interval semantics leading to off-by-one errors.
- error
Assuming a simple list scan is fast enough for 400 bookings, causing timeouts.
- error
Not updating both start and end counts, missing maximum k-booking correctly.
进阶变体
外企场景- arrow_right_alt
My Calendar II: track double bookings only, simpler overlap counting.
- arrow_right_alt
Counting overlaps with dynamic interval insertion and deletion, requiring interval trees.
- arrow_right_alt
Generalized maximum overlap queries over multiple calendars for real-time scheduling.