我的日程安排表-i
Tips
题目类型: 线段树
题目
实现一个 MyCalendar
类来存放你的日程安排. 如果要添加的日程安排不会造成重复预订, 则可以存储这个新的日程安排.
当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内), 就会产生重复预订.
日程可以用一对整数 start 和 end 表示, 这里的时间是半开区间, 即 [start, end)
, 实数 x 的范围为 start <= x < end
.
实现 MyCalendar
类:
MyCalendar()
初始化日历对象.boolean book(int start, int end)
如果可以将日程安排成功添加到日历中而不会导致重复预订, 返回true
.否则, 返回false
并且不要将该日程安排添加到日历中.
示例
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.
题解
- JavaScript- 朴素解法
- JavaScript - 线段树
var MyCalendar = function () {
this.books = []
}
/**
* @param {number} start
* @param {number} end
* @return {boolean}
*/
MyCalendar.prototype.book = function (start, end) {
for (const book of this.books) {
const [s, e] = book
if (s < end && start < e) {
return false
}
}
this.books.push([start, end])
return true
}
/**
* Your MyCalendar object will be instantiated and called as such:
* var obj = new MyCalendar()
* var param_1 = obj.book(start,end)
*/
-
时间复杂度: O(n2), 其中 n 表示日程安排的数量. 由于每次在进行预订时, 都需要遍历所有已经预订的行程安排.
-
空间复杂度: O(n), 其中 n 表示日程安排的数量. 需要保存所有已经预订的行程.
利用线段树, 初始化成 0, 将已预定的标记为 1, 如果有重复预定的就容易看出了.
var MyCalendar = function () {
this.tree = new Set()
this.lazy = new Set()
}
MyCalendar.prototype.book = function (start, end) {
if (this.query(start, end - 1, 0, 1000000000, 1)) {
return false
}
this.update(start, end - 1, 0, 1000000000, 1)
return true
}
MyCalendar.prototype.query = function (start, end, l, r, idx) {
if (start > r || end < l) {
return false
}
/* 如果该区间已被预订, 则直接返回 */
if (this.lazy.has(idx)) {
return true
}
if (start <= l && r <= end) {
return this.tree.has(idx)
} else {
const mid = (l + r) >> 1
if (end <= mid) {
return this.query(start, end, l, mid, 2 * idx)
} else if (start > mid) {
return this.query(start, end, mid + 1, r, 2 * idx + 1)
} else {
return (
this.query(start, end, l, mid, 2 * idx) |
this.query(start, end, mid + 1, r, 2 * idx + 1)
)
}
}
}
MyCalendar.prototype.update = function (start, end, l, r, idx) {
if (r < start || end < l) {
return
}
if (start <= l && r <= end) {
this.tree.add(idx)
this.lazy.add(idx)
} else {
const mid = (l + r) >> 1
this.update(start, end, l, mid, 2 * idx)
this.update(start, end, mid + 1, r, 2 * idx + 1)
this.tree.add(idx)
}
}
-
时间复杂度: O(nlogC), 其中 n 为日程安排的数量. 由于使用了线段树查询, 线段树的最大深度为 logC, 每次最多会查询 logC 个节点, 每次求最大的预订需的时间复杂度为 O(logC + logC), 因此时间复杂度为 O(nlogC), 在此 C 取固定值 109.
-
空间复杂度: O(nlogC), 其中 n 为日程安排的数量由于该解法采用的为动态线段树, 线段树的最大深度为 logC, 每次预订最多会在线段树上增加 logC 个节点, 因此空间复杂度为 O(nlogC), 在此 C 取固定值 109.