@@ -54,159 +54,176 @@ class Solution:
54
54
### 思路 2:线段树代码
55
55
56
56
``` Python
57
- class TreeNode :
57
+ # 线段树的节点类
58
+ class SegTreeNode :
58
59
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
+
65
66
# 线段树类
66
67
class SegmentTree :
68
+ # 初始化线段树接口
67
69
def __init__ (self , nums , function ):
68
70
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 是一个函数,左右区间的聚合方法
72
74
if self .size > 0 :
73
75
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]
76
100
def __build (self , index , left , right ):
77
101
self .tree[index].left = left
78
102
self .tree[index].right = right
79
- if left == right: # 叶子节点,节点值为对应位置的元素值
103
+ if left == right: # 叶子节点,节点值为对应位置的元素值
80
104
self .tree[index].val = self .nums[left]
81
105
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
105
121
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
150
141
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 ) # 当前节点所在区间大小
153
144
self .tree[index].val += val * interval_size # 当前节点所在区间每个元素值增加 val
154
145
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] 无关
156
170
return 0
157
-
171
+
158
172
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)
159
191
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 的节点所在区间的左右子节点的值和懒惰标记
171
193
def __pushdown (self , index ):
172
194
lazy_tag = self .tree[index].lazy_tag
173
- if not lazy_tag:
195
+ if lazy_tag is None :
174
196
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 :
180
202
self .tree[left_index].lazy_tag += lazy_tag # 更新左子节点懒惰标记
181
203
else :
182
204
self .tree[left_index].lazy_tag = lazy_tag
183
205
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 # 更新右子节点懒惰标记
188
210
else :
189
211
self .tree[right_index].lazy_tag = lazy_tag
190
212
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 # 更新当前节点的懒惰标记
192
216
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
200
217
201
218
class Solution :
202
219
def busyStudent (self , startTime : List[int ], endTime : List[int ], queryTime : int ) -> int :
203
220
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))
205
222
size = len (startTime)
206
223
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 )
208
225
209
- return self .ST .query_interval(queryTime, queryTime)
226
+ return self .STree .query_interval(queryTime, queryTime)
210
227
```
211
228
212
229
### 思路 3:树状数组
0 commit comments