@@ -165,9 +165,11 @@ tags:
165165<!-- solution:start -->
166166
167167### 方法一:双 Deque 维护窗口最大值与最小值
168+
168169本题要求计算所有长度不超过 $k$ 的子数组中:
169- * 子数组最大值之和
170- * 子数组最小值之和
170+
171+ - 子数组最大值之和
172+ - 子数组最小值之和
171173
172174并返回两者之和。
173175
188190表示所有以索引 $i$ 结尾的合法子数组,它们各自最小值的总和。
189191
190192接下来,我们维护两个单调队列:
191- * ` max_stack ` :维护当前窗口内所有子数组可能的最大值。
192- * ` min_stack ` :维护当前窗口内所有子数组可能的最小值。
193+
194+ - ` max_stack ` :维护当前窗口内所有子数组可能的最大值。
195+ - ` min_stack ` :维护当前窗口内所有子数组可能的最小值。
193196
194197虽然底层数据结构为 ` deque ` ,但由于绝大多数操作都发生在右侧,因此其本质仍然是单调栈。
195198
196199队列中的每个元素格式为:
200+
197201``` text
198202(index, value, shares)
199203```
200204
201205其中:
202- * ` index ` :元素索引
203- * ` value ` :元素值
204- * ` shares ` :该元素在当前窗口内,作为子数组最大值 / 最小值的贡献次数
206+
207+ - ` index ` :元素索引
208+ - ` value ` :元素值
209+ - ` shares ` :该元素在当前窗口内,作为子数组最大值 / 最小值的贡献次数
205210
206211---
212+
207213#### Step 1. 边界管理
214+
208215当遍历到当前元素 ` nums[i] ` 时,我们首先需要确保窗口长度不超过 $k$。
209216
210217窗口左边界为:
216223若某元素索引已经小于该边界,说明其已经离开窗口,不再属于任何合法子数组。
217224
218225因此:
219- * ` max_stack ` 栈头元素若已越界,则弹出
220- * ` min_stack ` 栈头元素若已越界,则弹出
226+
227+ - ` max_stack ` 栈头元素若已越界,则弹出
228+ - ` min_stack ` 栈头元素若已越界,则弹出
221229
222230同时,需要从:
223- * ` subarrays_max_sum `
224- * ` subarrays_min_sum `
231+
232+ - ` subarrays_max_sum `
233+ - ` subarrays_min_sum `
225234
226235中扣除这些元素对应的贡献。
227236
228237---
238+
229239#### Step 2. 更新单调栈
240+
230241对于当前元素 ` nums[i] ` :
231242
232243若 ` max_stack ` 栈尾元素的值小于等于 ` nums[i] ` :
233244
234245说明这些元素已经不可能继续成为后续子数组的最大值。
235246
236247因此:
248+
2372491 . 持续弹出这些元素
2382502 . 将它们的贡献次数 ` shares ` 转移给 ` nums[i] `
2392513 . 更新 ` subarrays_max_sum `
240252
241253若弹出的元素为:
254+
242255``` text
243256(prev_idx, prev_num, prev_shares)
244257```
245258
246259则会对:
260+
247261``` text
248262subarrays_max_sum
249263```
259273随后,再加上当前元素自身形成的新子数组贡献。
260274
261275最后,将:
276+
262277``` text
263278(i, nums[i], shares)
264279```
280+
265281压入 ` max_stack ` 。
266282
267283---
284+
268285` min_stack ` 的操作方式完全相同。区别仅在于:
269- * ` max_stack ` 维护单调递减性质
270- * ` min_stack ` 维护单调递增性质
286+
287+ - ` max_stack ` 维护单调递减性质
288+ - ` min_stack ` 维护单调递增性质
271289
272290因此比较条件需要反转:
291+
273292``` text
274293max_stack: top_value <= nums[i]
275294min_stack: top_value >= nums[i]
276295```
277296
278297---
298+
279299#### Step 3. 累加答案
300+
280301当索引 $i$ 处理完成后:
281302
282- * ` subarrays_max_sum `
303+ - ` subarrays_max_sum `
283304 表示所有以 $i$ 结尾的合法子数组最大值总和
284- * ` subarrays_min_sum `
305+ - ` subarrays_min_sum `
285306 表示所有以 $i$ 结尾的合法子数组最小值总和
286307
287308因此我们将两者加入最终答案:
309+
288310``` text
289311subarrays_max_min_sum
290312```
313+
291314最终返回该结果即可。
292315
293316---
317+
294318时间复杂度为 $O(n)$,空间复杂度为 $O(n)$。
295319
296320这是因为:
297- * 每个元素至多进入并离开 ` max_stack ` 各一次
298- * 每个元素至多进入并离开 ` min_stack ` 各一次
321+
322+ - 每个元素至多进入并离开 ` max_stack ` 各一次
323+ - 每个元素至多进入并离开 ` min_stack ` 各一次
299324
300325因此每个元素总操作次数不超过四次,整体时间复杂度为严格线性时间复杂度。
301326
0 commit comments