Medium

题目描述

实现一个 MyCalendar 类来存放你的日程安排。如果要添加的日程安排不会造成 重复预订 ,则可以存储这个新的日程安排。

当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生 重复预订

日程可以用一对整数 startTimeendTime 表示,这里的时间是半开区间,即 [startTime, endTime), 实数 x 的范围为,startTime <= x < endTime

实现 MyCalendar 类:

  • MyCalendar() 初始化日历对象。
  • boolean book(int startTime, int endTime) 如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

示例:

输入:
["MyCalendar", "book", "book", "book"]
[[], [10, 20], [15, 25], [20, 30]]
输出:
[null, true, false, true]

解释:
MyCalendar myCalendar = new MyCalendar();
myCalendar.book(10, 20); // return True
myCalendar.book(15, 25); // return False ,这个日程安排不能添加到日历中,因为时间 15 已经被另一个日程安排预订了。
myCalendar.book(20, 30); // return True ,这个日程安排可以添加到日历中,因为第一个日程安排预订的每个时间都小于 20 ,且不包含时间 20 。

提示:

  • 0 <= start < end <= 10^9
  • 每个测试用例,调用 book 方法的次数最多不超过 1000 次。

解题思路

解题思路

这道题要求实现一个日程安排系统,核心是判断新的时间段是否与已存在的时间段冲突。

方法一:暴力法(推荐)

最直观的方法是维护一个已预订时间段的列表,每次添加新预订时,遍历所有已存在的时间段,检查是否有冲突。

冲突判断:两个时间段 [a, b)[c, d) 冲突的条件是:max(a, c) < min(b, d),等价于 a < d && c < b

方法二:有序集合 + 二分查找

将预订按起始时间排序,使用二分查找定位新预订的插入位置,只需检查相邻的时间段。这种方法在预订数量很大时更高效。

方法三:平衡二叉搜索树

使用 TreeMap 或 set 等数据结构维护有序的时间段,查找和插入的时间复杂度都是 O(log n)。

考虑到题目约束(最多1000次调用),暴力法已经足够高效且实现简单,因此推荐使用方法一。

代码实现

class MyCalendar {
private:
    vector<pair<int, int>> bookings;
    
public:
    MyCalendar() {
        
    }
    
    bool book(int startTime, int endTime) {
        for (auto& booking : bookings) {
            if (startTime < booking.second && endTime > booking.first) {
                return false;
            }
        }
        bookings.push_back({startTime, endTime});
        return true;
    }
};
class MyCalendar:

    def __init__(self):
        self.bookings = []

    def book(self, startTime: int, endTime: int) -> bool:
        for start, end in self.bookings:
            if startTime < end and endTime > start:
                return False
        self.bookings.append((startTime, endTime))
        return True
public class MyCalendar {
    private List<(int start, int end)> bookings;

    public MyCalendar() {
        bookings = new List<(int, int)>();
    }
    
    public bool Book(int startTime, int endTime) {
        foreach (var booking in bookings) {
            if (startTime < booking.end && endTime > booking.start) {
                return false;
            }
        }
        bookings.Add((startTime, endTime));
        return true;
    }
}
var MyCalendar = function() {
    this.bookings = [];
};

MyCalendar.prototype.book = function(startTime, endTime) {
    for (let booking of this.bookings) {
        if (startTime < booking[1] && endTime > booking[0]) {
            return false;
        }
    }
    this.bookings.push([startTime, endTime]);
    return true;
};

复杂度分析

方法时间复杂度空间复杂度
暴力法O(n) per book, O(n²) totalO(n)
二分查找O(n log n) per bookO(n)

其中 n 是已预订的时间段数量。对于题目给定的约束(最多1000次调用),暴力法的性能完全满足要求。

相关题目