返回
我的日程安排表系列算法题解析
见解分享
2023-09-29 22:33:36
我的日程安排表系列算法题解析
引言
《我的日程安排表》系列算法题是LeetCode上非常经典的题目,考察了数据结构和算法的基本功。这些题目难度适中,适合不同阶段的算法学习者。本文将对这三个题目进行详细解析,帮助读者深入理解它们。
729. 我的日程安排表 I
题目
给你一个时间范围,请你找出所有在这个时间范围内的事件。
思路分析:
这道题目可以用树状数组或者线段树来解决。树状数组是一种高效的数据结构,可以用于区间查询和单点更新。线段树是一种更加通用的数据结构,也可以用于区间查询和单点更新,但它的实现更加复杂。
代码实现(树状数组):
class MyCalendar {
int[] tree;
int n;
public MyCalendar() {
n = 1000000;
tree = new int[n];
}
public boolean book(int start, int end) {
if (query(end - 1) - query(start - 1) > 0) {
return false;
}
update(start, 1);
update(end, -1);
return true;
}
private void update(int idx, int val) {
while (idx < n) {
tree[idx] += val;
idx += lowbit(idx);
}
}
private int query(int idx) {
int sum = 0;
while (idx > 0) {
sum += tree[idx];
idx -= lowbit(idx);
}
return sum;
}
private int lowbit(int x) {
return x & (-x);
}
}
时间复杂度:
book
操作:O(log(n))query
操作:O(log(n))
空间复杂度:
O(n)
731. 我的日程安排表 II
题目:
给你一个时间范围,请你找出所有在这个时间范围内的重叠事件。
思路分析:
这道题目可以用线段树来解决。线段树是一种更加通用的数据结构,可以用于区间查询和单点更新。
代码实现:
class MyCalendarTwo {
class SegmentTreeNode {
int start, end;
int count;
int overlapCount;
SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end) {
this.start = start;
this.end = end;
this.count = 0;
this.overlapCount = 0;
this.left = null;
this.right = null;
}
}
SegmentTreeNode root;
public MyCalendarTwo() {
root = null;
}
public boolean book(int start, int end) {
if (root == null) {
root = new SegmentTreeNode(start, end);
return true;
}
return insert(root, start, end);
}
private boolean insert(SegmentTreeNode node, int start, int end) {
if (node.start == start && node.end == end) {
node.count++;
if (node.count == 1) {
node.overlapCount = 0;
return true;
} else if (node.count == 2) {
node.overlapCount = 1;
return false;
} else {
return false;
}
}
boolean result = true;
int mid = (node.start + node.end) / 2;
if (end <= mid) {
if (node.left == null) {
node.left = new SegmentTreeNode(node.start, mid);
}
result = insert(node.left, start, end);
} else if (start > mid) {
if (node.right == null) {
node.right = new SegmentTreeNode(mid + 1, node.end);
}
result = insert(node.right, start, end);
} else {
if (node.left == null) {
node.left = new SegmentTreeNode(node.start, mid);
}
if (node.right == null) {
node.right = new SegmentTreeNode(mid + 1, node.end);
}
result = insert(node.left, start, mid) && insert(node.right, mid + 1, end);
}
node.count = node.left != null ? node.left.count : 0;
node.count += node.right != null ? node.right.count : 0;
node.overlapCount = node.left != null ? node.left.overlapCount : 0;
node.overlapCount += node.right != null ? node.right.overlapCount : 0;
if (node.count == 2 && node.overlapCount == 0) {
node.overlapCount = 1;
result = false;
}
return result;
}
}
时间复杂度:
book
操作:O(log(n))
空间复杂度:
O(n)
732. 我的日程安排表 III
题目:
给你一个事件列表,其中每个事件都有一个开始时间和结束时间。请你找出可以在任何时间段内同时发生的事件数量的最大值。
思路分析:
这道题目可以用扫描线算法来解决。扫描线算法是一种用于解决区间重叠问题的算法。它将事件按时间顺序排序,然后从左到右扫描时间轴。在每个时间点,算法都会记录当前重叠的事件数。
代码实现:
class MyCalendarThree {
TreeMap<Integer, Integer> map;
public MyCalendarThree() {
map = new TreeMap<>();
}
public int book(int start, int end) {
map.put(start, map.getOrDefault(start, 0) + 1);
map.put(end, map.getOrDefault(end, 0) - 1);
int max = 0, sum = 0;
for (int value : map.values()) {
sum += value;
max = Math.max(max, sum);
}
return max;
}
}
时间复杂度:
book
操作:O(log(n))
空间复杂度:
O(n)
总结
《我的日程安排表》系列算法题考察了数据结构和算法的基本功。这三个题目难度适中,适合不同阶段的算法学习者。本文详细解析了这些题目,希望对读者有所帮助。