Skip to content

Commit 1fee32b

Browse files
author
杨世超
committed
Update 1450. 在既定时间做作业的学生人数.md
1 parent 934b009 commit 1fee32b

File tree

1 file changed

+133
-116
lines changed

1 file changed

+133
-116
lines changed

Solutions/1450. 在既定时间做作业的学生人数.md

Lines changed: 133 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -54,159 +54,176 @@ class Solution:
5454
### 思路 2:线段树代码
5555

5656
```Python
57-
class TreeNode:
57+
# 线段树的节点类
58+
class SegTreeNode:
5859
def __init__(self, val=0):
59-
self.left = -1 # 区间左边界
60-
self.right = -1 # 区间右边界
61-
self.val = val # 节点值(区间值)
62-
self.lazy_tag = None # 区间和问题的延迟更新标记
63-
64-
60+
self.left = -1 # 区间左边界
61+
self.right = -1 # 区间右边界
62+
self.val = val # 节点值(区间值)
63+
self.lazy_tag = None # 区间和问题的延迟更新标记
64+
65+
6566
# 线段树类
6667
class SegmentTree:
68+
# 初始化线段树接口
6769
def __init__(self, nums, function):
6870
self.size = len(nums)
69-
self.tree = [TreeNode() for _ in range(4 * self.size)] # 维护 TreeNode 数组
70-
self.nums = nums # 原始数据
71-
self.function = function # function 是一个函数,左右区间的聚合方法
71+
self.tree = [SegTreeNode() for _ in range(4 * self.size)] # 维护 SegTreeNode 数组
72+
self.nums = nums # 原始数据
73+
self.function = function # function 是一个函数,左右区间的聚合方法
7274
if self.size > 0:
7375
self.__build(0, 0, self.size - 1)
74-
75-
# 构建线段树,节点的存储下标为 index,节点的区间为 [left, right]
76+
77+
# 单点更新接口:将 nums[i] 更改为 val
78+
def update_point(self, i, val):
79+
self.nums[i] = val
80+
self.__update_point(i, val, 0)
81+
82+
# 区间更新接口:将区间为 [q_left, q_right] 上的所有元素值加上 val
83+
def update_interval(self, q_left, q_right, val):
84+
self.__update_interval(q_left, q_right, val, 0)
85+
86+
# 区间查询接口:查询区间为 [q_left, q_right] 的区间值
87+
def query_interval(self, q_left, q_right):
88+
return self.__query_interval(q_left, q_right, 0)
89+
90+
# 获取 nums 数组接口:返回 nums 数组
91+
def get_nums(self):
92+
for i in range(self.size):
93+
self.nums[i] = self.query_interval(i, i)
94+
return self.nums
95+
96+
97+
# 以下为内部实现方法
98+
99+
# 构建线段树实现方法:节点的存储下标为 index,节点的区间为 [left, right]
76100
def __build(self, index, left, right):
77101
self.tree[index].left = left
78102
self.tree[index].right = right
79-
if left == right: # 叶子节点,节点值为对应位置的元素值
103+
if left == right: # 叶子节点,节点值为对应位置的元素值
80104
self.tree[index].val = self.nums[left]
81105
return
82-
83-
mid = left + (right - left) // 2 # 左右节点划分点
84-
left_index = index * 2 + 1 # 左子节点的存储下标
85-
right_index = index * 2 + 2 # 右子节点的存储下标
86-
self.__build(left_index, left, mid) # 递归创建左子树
87-
self.__build(right_index, mid + 1, right) # 递归创建右子树
88-
self.__pushup(index) # 向上更新节点的区间值
89-
90-
# 向上更新下标为 index 的节点区间值,节点的区间值等于该节点左右子节点元素值的聚合计算结果
91-
def __pushup(self, index):
92-
left_index = index * 2 + 1 # 左子节点的存储下标
93-
right_index = index * 2 + 2 # 右子节点的存储下标
94-
self.tree[index].val = self.function(self.tree[left_index].val, self.tree[right_index].val)
95-
96-
# 单点更新,将 nums[i] 更改为 val
97-
def update_point(self, i, val):
98-
self.nums[i] = val
99-
self.__update_point(i, val, 0, 0, self.size - 1)
100-
101-
# 单点更新,将 nums[i] 更改为 val。节点的存储下标为 index,节点的区间为 [left, right]
102-
def __update_point(self, i, val, index, left, right):
103-
if self.tree[index].left == self.tree[index].right:
104-
self.tree[index].val = val # 叶子节点,节点值修改为 val
106+
107+
mid = left + (right - left) // 2 # 左右节点划分点
108+
left_index = index * 2 + 1 # 左子节点的存储下标
109+
right_index = index * 2 + 2 # 右子节点的存储下标
110+
self.__build(left_index, left, mid) # 递归创建左子树
111+
self.__build(right_index, mid + 1, right) # 递归创建右子树
112+
self.__pushup(index) # 向上更新节点的区间值
113+
114+
# 单点更新实现方法:将 nums[i] 更改为 val,节点的存储下标为 index
115+
def __update_point(self, i, val, index):
116+
left = self.tree[index].left
117+
right = self.tree[index].right
118+
119+
if left == right:
120+
self.tree[index].val = val # 叶子节点,节点值修改为 val
105121
return
106-
107-
mid = left + (right - left) // 2 # 左右节点划分点
108-
left_index = index * 2 + 1 # 左子节点的存储下标
109-
right_index = index * 2 + 2 # 右子节点的存储下标
110-
if i <= mid: # 在左子树中更新节点值
111-
self.__update_point(i, val, left_index, left, mid)
112-
else: # 在右子树中更新节点值
113-
self.__update_point(i, val, right_index, mid + 1, right)
114-
self.__pushup(index) # 向上更新节点的区间值
115-
116-
# 区间查询,查询区间为 [q_left, q_right] 的区间值
117-
def query_interval(self, q_left, q_right):
118-
return self.__query_interval(q_left, q_right, 0, 0, self.size - 1)
119-
120-
# 区间查询,在线段树的 [left, right] 区间范围中搜索区间为 [q_left, q_right] 的区间值
121-
def __query_interval(self, q_left, q_right, index, left, right):
122-
if left >= q_left and right <= q_right: # 节点所在区间被 [q_left, q_right] 所覆盖
123-
return self.tree[index].val # 直接返回节点值
124-
if right < q_left or left > q_right: # 节点所在区间与 [q_left, q_right] 无关
125-
return 0
126-
127-
self.__pushdown(index)
128-
129-
mid = left + (right - left) // 2 # 左右节点划分点
130-
left_index = index * 2 + 1 # 左子节点的存储下标
131-
right_index = index * 2 + 2 # 右子节点的存储下标
132-
res_left = 0 # 左子树查询结果
133-
res_right = 0 # 右子树查询结果
134-
if q_left <= mid: # 在左子树中查询
135-
res_left = self.__query_interval(q_left, q_right, left_index, left, mid)
136-
if q_right > mid: # 在右子树中查询
137-
res_right = self.__query_interval(q_left, q_right, right_index, mid + 1, right)
138-
return self.function(res_left, res_right) # 返回左右子树元素值的聚合计算结果
139-
140-
# 区间更新,将区间为 [q_left, q_right] 上的元素值修改为 val
141-
def update_interval(self, q_left, q_right, val):
142-
self.__update_interval(q_left, q_right, val, 0, 0, self.size - 1)
143-
144-
# 区间更新
145-
def __update_interval(self, q_left, q_right, val, index, left, right):
146-
147-
if left >= q_left and right <= q_right: # 节点所在区间被 [q_left, q_right] 所覆盖
148-
if self.tree[index].lazy_tag:
149-
self.tree[index].lazy_tag += val # 将当前节点的延迟标记增加 val
122+
123+
mid = left + (right - left) // 2 # 左右节点划分点
124+
left_index = index * 2 + 1 # 左子节点的存储下标
125+
right_index = index * 2 + 2 # 右子节点的存储下标
126+
if i <= mid: # 在左子树中更新节点值
127+
self.__update_point(i, val, left_index)
128+
else: # 在右子树中更新节点值
129+
self.__update_point(i, val, right_index)
130+
131+
self.__pushup(index) # 向上更新节点的区间值
132+
133+
# 区间更新实现方法
134+
def __update_interval(self, q_left, q_right, val, index):
135+
left = self.tree[index].left
136+
right = self.tree[index].right
137+
138+
if left >= q_left and right <= q_right: # 节点所在区间被 [q_left, q_right] 所覆盖
139+
if self.tree[index].lazy_tag is not None:
140+
self.tree[index].lazy_tag += val # 将当前节点的延迟标记增加 val
150141
else:
151-
self.tree[index].lazy_tag = val # 将当前节点的延迟标记增加 val
152-
interval_size = (right - left + 1) # 当前节点所在区间大小
142+
self.tree[index].lazy_tag = val # 将当前节点的延迟标记增加 val
143+
interval_size = (right - left + 1) # 当前节点所在区间大小
153144
self.tree[index].val += val * interval_size # 当前节点所在区间每个元素值增加 val
154145
return
155-
if right < q_left or left > q_right: # 节点所在区间与 [q_left, q_right] 无关
146+
147+
if right < q_left or left > q_right: # 节点所在区间与 [q_left, q_right] 无关
148+
return
149+
150+
self.__pushdown(index) # 向下更新节点的区间值
151+
152+
mid = left + (right - left) // 2 # 左右节点划分点
153+
left_index = index * 2 + 1 # 左子节点的存储下标
154+
right_index = index * 2 + 2 # 右子节点的存储下标
155+
if q_left <= mid: # 在左子树中更新区间值
156+
self.__update_interval(q_left, q_right, val, left_index)
157+
if q_right > mid: # 在右子树中更新区间值
158+
self.__update_interval(q_left, q_right, val, right_index)
159+
160+
self.__pushup(index) # 向上更新节点的区间值
161+
162+
# 区间查询实现方法:在线段树中搜索区间为 [q_left, q_right] 的区间值
163+
def __query_interval(self, q_left, q_right, index):
164+
left = self.tree[index].left
165+
right = self.tree[index].right
166+
167+
if left >= q_left and right <= q_right: # 节点所在区间被 [q_left, q_right] 所覆盖
168+
return self.tree[index].val # 直接返回节点值
169+
if right < q_left or left > q_right: # 节点所在区间与 [q_left, q_right] 无关
156170
return 0
157-
171+
158172
self.__pushdown(index)
173+
174+
mid = left + (right - left) // 2 # 左右节点划分点
175+
left_index = index * 2 + 1 # 左子节点的存储下标
176+
right_index = index * 2 + 2 # 右子节点的存储下标
177+
res_left = 0 # 左子树查询结果
178+
res_right = 0 # 右子树查询结果
179+
if q_left <= mid: # 在左子树中查询
180+
res_left = self.__query_interval(q_left, q_right, left_index)
181+
if q_right > mid: # 在右子树中查询
182+
res_right = self.__query_interval(q_left, q_right, right_index)
183+
184+
return self.function(res_left, res_right) # 返回左右子树元素值的聚合计算结果
185+
186+
# 向上更新实现方法:更新下标为 index 的节点区间值 等于 该节点左右子节点元素值的聚合计算结果
187+
def __pushup(self, index):
188+
left_index = index * 2 + 1 # 左子节点的存储下标
189+
right_index = index * 2 + 2 # 右子节点的存储下标
190+
self.tree[index].val = self.function(self.tree[left_index].val, self.tree[right_index].val)
159191

160-
mid = left + (right - left) // 2 # 左右节点划分点
161-
left_index = index * 2 + 1 # 左子节点的存储下标
162-
right_index = index * 2 + 2 # 右子节点的存储下标
163-
if q_left <= mid: # 在左子树中更新区间值
164-
self.__update_interval(q_left, q_right, val, left_index, left, mid)
165-
if q_right > mid: # 在右子树中更新区间值
166-
self.__update_interval(q_left, q_right, val, right_index, mid + 1, right)
167-
168-
self.__pushup(index)
169-
170-
# 向下更新下标为 index 的节点所在区间的左右子节点的值和懒惰标记
192+
# 向下更新实现方法:更新下标为 index 的节点所在区间的左右子节点的值和懒惰标记
171193
def __pushdown(self, index):
172194
lazy_tag = self.tree[index].lazy_tag
173-
if not lazy_tag:
195+
if lazy_tag is None:
174196
return
175-
176-
left_index = index * 2 + 1 # 左子节点的存储下标
177-
right_index = index * 2 + 2 # 右子节点的存储下标
178-
179-
if self.tree[left_index].lazy_tag:
197+
198+
left_index = index * 2 + 1 # 左子节点的存储下标
199+
right_index = index * 2 + 2 # 右子节点的存储下标
200+
201+
if self.tree[left_index].lazy_tag is not None:
180202
self.tree[left_index].lazy_tag += lazy_tag # 更新左子节点懒惰标记
181203
else:
182204
self.tree[left_index].lazy_tag = lazy_tag
183205
left_size = (self.tree[left_index].right - self.tree[left_index].left + 1)
184-
self.tree[left_index].val += lazy_tag * left_size # 左子节点每个元素值增加 lazy_tag
185-
186-
if self.tree[right_index].lazy_tag:
187-
self.tree[right_index].lazy_tag += lazy_tag # 更新右子节点懒惰标记
206+
self.tree[left_index].val += lazy_tag * left_size # 左子节点每个元素值增加 lazy_tag
207+
208+
if self.tree[right_index].lazy_tag is not None:
209+
self.tree[right_index].lazy_tag += lazy_tag # 更新右子节点懒惰标记
188210
else:
189211
self.tree[right_index].lazy_tag = lazy_tag
190212
right_size = (self.tree[right_index].right - self.tree[right_index].left + 1)
191-
self.tree[right_index].val += lazy_tag * right_size # 右子节点每个元素值增加 lazy_tag
213+
self.tree[right_index].val += lazy_tag * right_size # 右子节点每个元素值增加 lazy_tag
214+
215+
self.tree[index].lazy_tag = None # 更新当前节点的懒惰标记
192216

193-
self.tree[index].lazy_tag = None # 更新当前节点的懒惰标记
194-
195-
# 获取 nums 数组
196-
def get_nums(self):
197-
for i in range(self.size):
198-
self.nums[i] = self.query_interval(i, i)
199-
return self.nums
200217

201218
class Solution:
202219
def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
203220
nums = [0 for _ in range(1010)]
204-
self.ST = SegmentTree(nums, lambda x, y: max(x, y))
221+
self.STree = SegmentTree(nums, lambda x, y: max(x, y))
205222
size = len(startTime)
206223
for i in range(size):
207-
self.ST.update_interval(startTime[i], endTime[i], 1)
224+
self.STree.update_interval(startTime[i], endTime[i], 1)
208225

209-
return self.ST.query_interval(queryTime, queryTime)
226+
return self.STree.query_interval(queryTime, queryTime)
210227
```
211228

212229
### 思路 3:树状数组

0 commit comments

Comments
 (0)