持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
题目
实现一个 MyCalendar 类来存放你的日程安排。如果要添加的日程安排不会造成 重复预订 ,则可以存储这个新的日程安排。
当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生 重复预订 。
日程可以用一对整数 start 和 end 表示,这里的时间是半开区间,即 [start, end), 实数 x 的范围为, start <= x < end 。
实现 MyCalendar 类:
MyCalendar()初始化日历对象。boolean book(int start, int end)如果可以将日程安排成功添加到日历中而不会导致重复预订,返回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次。
思考
本题难度中等。
首先是读懂题意。重复预订是指两个日程安排有一些时间上的交叉。我们可以在每次新加一个日程时,遍历是否与之前的日程存在交叉即可,也就是暴力解法。
此外,可以使用二分查找的方法解决。定义日程数组events,最小值为0,最大值为events.length - 1,通过二分查找,如果start < this.events[guess][1] && this.events[guess][0] < end,则重复预订了。否则继续二分查找,直至找到与日程[start, end]相邻的最小区间,并插入日程[start, end]即可。
解答
方法一:暴力法
var MyCalendar = function() {
this.calendar = []
}
/**
* @param {number} start
* @param {number} end
* @return {boolean}
*/
MyCalendar.prototype.book = function(start, end) {
for (let item of this.calendar) {
if (item[0] < end && start < item[1]) return false
}
this.calendar.push([start, end])
return true
}
// 执行用时:188 ms, 在所有 JavaScript 提交中击败了36.96%的用户
// 内存消耗:49.9 MB, 在所有 JavaScript 提交中击败了57.97%的用户
// 通过测试用例:107 / 107
复杂度分析:
- 时间复杂度:,其中 n 指的是日常安排的数量。
- 空间复杂度:
O(n)。
方法二:二分查找
var MyCalendar = function() {
this.events = [];
};
MyCalendar.prototype.book = function(start, end) {
var min = 0;
var max = this.events.length - 1;
var guess;
while (min <= max) {
var guess = Math.floor((min + max) / 2);
if (start < this.events[guess][1] && this.events[guess][0] < end) {
return false;
} else if (this.events[guess][1] > start) {
min = guess + 1;
} else {
max = guess - 1;
}
}
// 在索引min处插入[start, end]
this.events.splice(min, 0, [start, end]);
return true;
};
// 执行用时:136 ms, 在所有 JavaScript 提交中击败了93.81%的用户
// 内存消耗:49.6 MB, 在所有 JavaScript 提交中击败了75.77%的用户
// 通过测试用例:107 / 107
复杂度分析:
- 时间复杂度:
O(nlogm),n 指的是日常安排的数量。二分查找需要执行 O(logm) 轮,需要进行 n 次二分查找。 - 空间复杂度:
O(n)。