Skip to content

Commit

Permalink
feat: add solutions to lc problem: No.0732 (#3921)
Browse files Browse the repository at this point in the history
No.0732.My Calendar III
  • Loading branch information
yanglbme authored Jan 4, 2025
1 parent ef0677c commit 7070b1f
Show file tree
Hide file tree
Showing 5 changed files with 413 additions and 42 deletions.
152 changes: 136 additions & 16 deletions solution/0700-0799/0732.My Calendar III/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,21 @@ myCalendarThree.book(25, 55); // 返回 3

### 方法一:线段树

线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(width)$。更新某个元素的值,只需要更新 $log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(\text{width})$。更新某个元素的值,只需要更新 $log(\text{width})$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。

- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 $[1,N]$;
- 线段树的每个叶子节点代表一个长度为 $1$ 的元区间 $[x, x]$;
- 对于每个内部节点 $[l,r]$,它的左儿子是 $[l,mid]$,右儿子是 $[mid+1,r]$, 其中 $mid = ⌊(l+r)/2⌋$ (即向下取整)。
- 对于每个内部节点 $[l,r]$,它的左儿子是 $[l,\text{mid}]$,右儿子是 $[\text{mid}+1,r]$, 其中 $\text{mid} = ⌊(l+r)/2⌋$ (即向下取整)。

对于本题,线段树节点维护的信息有:

1. 区间范围内被预定的次数的最大值 $v$
1. 懒标记 $add$
1. 懒标记 $\text{add}$

由于时间范围为 $10^9$,非常大,因此我们采用动态开点。

时间复杂度 $O(nlogn)$,其中 $n$ 表示日程安排的数量。
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$,其中 $n$ 表示日程安排的数量。

<!-- tabs:start -->

Expand All @@ -105,7 +105,7 @@ class SegmentTree:
def __init__(self):
self.root = Node(1, int(1e9 + 1))

def modify(self, l, r, v, node=None):
def modify(self, l: int, r: int, v: int, node: Node = None):
if l > r:
return
if node is None:
Expand All @@ -121,7 +121,7 @@ class SegmentTree:
self.modify(l, r, v, node.right)
self.pushup(node)

def query(self, l, r, node=None):
def query(self, l: int, r: int, node: Node = None) -> int:
if l > r:
return 0
if node is None:
Expand All @@ -136,10 +136,10 @@ class SegmentTree:
v = max(v, self.query(l, r, node.right))
return v

def pushup(self, node):
def pushup(self, node: Node):
node.v = max(node.left.v, node.right.v)

def pushdown(self, node):
def pushdown(self, node: Node):
if node.left is None:
node.left = Node(node.l, node.mid)
if node.right is None:
Expand Down Expand Up @@ -312,15 +312,21 @@ public:
}

void modify(int l, int r, int v, Node* node) {
if (l > r) return;
if (l > r) {
return;
}
if (node->l >= l && node->r <= r) {
node->v += v;
node->add += v;
return;
}
pushdown(node);
if (l <= node->mid) modify(l, r, v, node->left);
if (r > node->mid) modify(l, r, v, node->right);
if (l <= node->mid) {
modify(l, r, v, node->left);
}
if (r > node->mid) {
modify(l, r, v, node->right);
}
pushup(node);
}

Expand All @@ -329,12 +335,18 @@ public:
}

int query(int l, int r, Node* node) {
if (l > r) return 0;
if (l > r) {
return 0;
}
if (node->l >= l && node->r <= r) return node->v;
pushdown(node);
int v = 0;
if (l <= node->mid) v = max(v, query(l, r, node->left));
if (r > node->mid) v = max(v, query(l, r, node->right));
if (l <= node->mid) {
v = max(v, query(l, r, node->left));
}
if (r > node->mid) {
v = max(v, query(l, r, node->right));
}
return v;
}

Expand All @@ -343,8 +355,12 @@ public:
}

void pushdown(Node* node) {
if (!node->left) node->left = new Node(node->l, node->mid);
if (!node->right) node->right = new Node(node->mid + 1, node->r);
if (!node->left) {
node->left = new Node(node->l, node->mid);
}
if (!node->right) {
node->right = new Node(node->mid + 1, node->r);
}
if (node->add) {
Node* left = node->left;
Node* right = node->right;
Expand Down Expand Up @@ -483,6 +499,110 @@ func (this *MyCalendarThree) Book(start int, end int) int {
*/
```

#### TypeScript

```ts
class Node {
left: Node | null = null;
right: Node | null = null;
l: number;
r: number;
mid: number;
v: number = 0;
add: number = 0;

constructor(l: number, r: number) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}

class SegmentTree {
private root: Node = new Node(1, 1e9 + 1);

constructor() {}

modify(l: number, r: number, v: number, node: Node = this.root): void {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v += v;
node.add += v;
return;
}
this.pushdown(node);
if (l <= node.mid) {
this.modify(l, r, v, node.left!);
}
if (r > node.mid) {
this.modify(l, r, v, node.right!);
}
this.pushup(node);
}

query(l: number, r: number, node: Node = this.root): number {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
this.pushdown(node);
let v = 0;
if (l <= node.mid) {
v = Math.max(v, this.query(l, r, node.left!));
}
if (r > node.mid) {
v = Math.max(v, this.query(l, r, node.right!));
}
return v;
}

private pushup(node: Node): void {
node.v = Math.max(node.left!.v, node.right!.v);
}

private pushdown(node: Node): void {
if (node.left === null) {
node.left = new Node(node.l, node.mid);
}
if (node.right === null) {
node.right = new Node(node.mid + 1, node.r);
}
if (node.add !== 0) {
const left = node.left!;
const right = node.right!;
left.add += node.add;
right.add += node.add;
left.v += node.add;
right.v += node.add;
node.add = 0;
}
}
}

class MyCalendarThree {
private tree: SegmentTree;

constructor() {
this.tree = new SegmentTree();
}

book(start: number, end: number): number {
this.tree.modify(start + 1, end, 1);
return this.tree.query(1, 1e9 + 1);
}
}

/**
* Your MyCalendarThree object will be instantiated and called as such:
* var obj = new MyCalendarThree()
* var param_1 = obj.book(startTime, endTime)
*/
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Loading

0 comments on commit 7070b1f

Please sign in to comment.