leetcode update

This commit is contained in:
gameloader 2024-09-26 13:23:25 +08:00
parent 57ebd283c8
commit e6e6b222f8

View File

@ -14103,3 +14103,120 @@ public:
} }
}; };
``` ```
## day212 2024-09-26
### 729. My Calendar I
You are implementing a program to use as your calendar. We can add a new event if adding the event will not cause a double booking.
A double booking happens when two events have some non-empty intersection (i.e., some moment is common to both events.).
The event can be represented as a pair of integers start and end that represents a booking on the half-open interval [start, end), the range of real numbers x such that start <= x < end.
Implement the MyCalendar class:
MyCalendar() Initializes the calendar object.
boolean book(int start, int end) Returns true if the event can be added to the calendar successfully without causing a double booking. Otherwise, return false and do not add the event to the calendar.
![09266fkystmmNuG2](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/09266fkystmmNuG2.png)
### 题解
本题涉及到区间问题可以使用线段树。在熟悉线段树结构的情况下本题非常容易解决只需查询book中出现的区间在线段树中查询得到的区间和是否为0即可知道该区间是否被覆盖过如果为0说明区间完全没有被覆盖则可以预订并更新对应区间的值这里可以给区间所有值加一在线段树中这个操作并不会真的将全部节点都加1而是会存在懒操作只要在覆盖这个区间的节点内加入标记记录了存在加1操作。非0则区间可能被部分覆盖即有冲突则不能预订。
关键的部分在线段树的实现,这里我们使用动态开点的线段树并使用懒标记。
### 代码
```cpp
class MyCalendar {
private:
struct Node {
Node* left;
Node* right;
int val;
int lazy;
Node() : left(nullptr), right(nullptr), val(0), lazy(0) {}
};
Node* root;
const int MAX_RANGE = 1e9;
void pushDown(Node* node, int start, int end) {
if (!node->left) node->left = new Node();
if (!node->right) node->right = new Node();
if (node->lazy) {
int mid = start + (end - start) / 2;
node->left->val += node->lazy;
node->left->lazy += node->lazy;
node->right->val += node->lazy;
node->right->lazy += node->lazy;
node->lazy = 0;
}
}
int query(Node* node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node->val;
pushDown(node, start, end);
int mid = start + (end - start) / 2;
int res = 0;
if (l <= mid) res += query(node->left, start, mid, l, r);
if (r > mid) res += query(node->right, mid + 1, end, l, r);
return res;
}
void update(Node* node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node->val += val;
node->lazy += val;
return;
}
pushDown(node, start, end);
int mid = start + (end - start) / 2;
if (l <= mid) update(node->left, start, mid, l, r, val);
if (r > mid) update(node->right, mid + 1, end, l, r, val);
node->val = max(node->left->val, node->right->val);
}
public:
MyCalendar() {
root = new Node();
}
bool book(int start, int end) {
if (query(root, 0, MAX_RANGE, start, end - 1) > 0) {
return false;
}
update(root, 0, MAX_RANGE, start, end - 1, 1);
return true;
}
};
```
### 总结
本题也可以使用简单的二分法求解将book中的每个区间加入到一个有序set中。对当前book区间在set中通过二分快速查找到第一个已经存在的区间的结束时间大于该区间的开始和结束时间其余情况或者和该区间有重合或者位于该区间前不会影响该区间的插入。再判断找到的这个区间的开始时间和当前book区间的结束时间的大小如果小于则有覆盖大于等于则无覆盖说明当前book区间可以预订将其插入到这个有序set中。代码如下
```cpp
class MyCalendar {
struct Node {
int start, end;
Node(int start, int end) : start(start), end(end) {}
bool operator<(const Node& other) const { return other.start >= end; }
};
set<Node> s;
public:
MyCalendar() {}
bool book(int start, int end) {
auto it = s.lower_bound({start, end});
if (it != s.end() && it->start < end)
return false;
s.insert({start, end});
return true;
}
};
```