如果类中存在__init__ (self), 初始化函数,
则对类建立对象时, 会对该对象先进行初始化函数的调用;
长度为 N 的数组, 使用一个 长度为 K 的 窗口进行滑动, 每次窗口移动的步长 为stride ;
此时, 输出的个数 = 总共滑动的窗口数 = N - k + stride
3. code
class Dequeue:
def __init__(self):
self.queue = []
# pop作用, 移除窗口中的第一个元素;
def pop(self, value ) -> int: # 队列中弹出元素时, 是将数组中传来的元素 与 队列的队首元素比较, 是否相等;
if self.queue and value == self.queue[0]: # if, 满足条件,执行一次; 若两者相等, 弹出队列的队首元素; if
return self.queue.pop(0)
# 该push 的 作用保证,传入的元素 小于 队列末尾的元素, 从而形成一个单调队列, 顺序从大到小;
def push(self, value) -> None: # 队列中存入元素时, 将传来的元素与队列中的 队尾元素进行比较;
while self.queue and value > self.queue[-1]: # 循环, 当单调队列不为空, 且数组中传来的元素 大于 队列末尾的元素时, 则移除队列的末尾元素;
self.queue.pop(-1) # 注意这里!!! 这里使用的数组自身内置的pop 函数;
self.queue.append(value) # 当数组中 传来的数值 小于 此时的队列末尾时, 将传来的数值存入 队列中;
def getFront(self, ) -> int:
return self.queue[0]
class Solution:
def maxSlidingWindow(self, nums: list, k : int) -> list:
cur_que = Dequeue() # 将双端队列实例化,用作 单调队列;
result = [] # 用于存放每次窗口中的 最大数;
for i in range(k): # 先在第一个窗口中, 将 单端队列初始化 赋值;
cur_que.push(nums[i]) # 将第一个窗口中, 满足条件的数值 压入到 单端队列中;
result.append(cur_que.getFront())
for i in range(k, len(nums)): # i 此时代表数组中元素的下标, i 从 k 开始;
cur_que.pop( nums[i- k]) # nums[i - k] : 代表当前窗口中 的第一个元素, i - k : 代表当前窗口中的第一个元素在 数组中的下标数值;
cur_que.push(nums[i]) # nums[i] : 代表当前窗口 向后移动时, 需要加入的元素;
result.append(cur_que.getFront()) # 存入当前窗口中 最大值;
return result
1. 单调队列
单调队列是双端队列中的其中一种情况, 单调队列中的元素按照递增或者递减的顺序;
注意本题中, 使用单调队列的末尾作为入口处, 队列的头部作为出口处,
并且该单调队列的特点是, 队首位置只会存放当前窗口内的最大数值;
1.1 先初始化单调队列
使用单调队列时, 先初始化单调队列,
先将第一个窗口中前K 个元素, 存入到队列中;
将当前队列中的最大值,压入到结果集中;
1.2 单调队列的作用与维护
在每一次移动窗口的过程中, 需要对该单调队列进行维护:
-
当队列满足条件时, 从队列中移除当前窗口中第一个元素, 以此来代表窗口向后移动了一个元素;
(满足的条件是: 队列中队首元素 == 当前窗口的第一个元素, 如果队列的首元素, 不等于 当前窗口的第一个元素, 则不移除元素; 为什么只有是首元素,才会移除呢? 因为 单调队列的首元素代表的是最大值, 即 如果当前窗口的首元素恰好是 最大值, 但是现在窗口向后移动了, 它不属于下一个窗口中的数值了, 因此它不能作为下一个窗口中的最大值而存在,应该去除掉;) -
添加窗口外的后一个元素到队列中: 当单调队列满足条件时, 将当前窗口外的后面一个元素加入到队列尾部;
(单调队列需要满足的条件是: 队列尾部的元素需要大于等于 待存入的元素; 如果当前尾部的元素 小于 待存入元素, 则一直将队尾元素移除, 直到大于等于待存入元素为止 或者 队列中为空 ) -
取出当前队列中的最大值, 存入到结果集中, 表明移动窗口后,当前窗口的最大值;
2. 窗口中元素的表示
每次窗口移动时, 窗口的两种元素会与单调队列有关;
- 当前窗口中的第一个元素, 需要从队列中移除;
- 当前窗口外的后一个元素, 需要加入到队列中;
根据以上两种元素, 来维护更新该队列;
那么问题来了, 如何表示出 上面两种 窗口中的元素;
即移动窗口的过程中, 如何表示出:
1. 当前 窗口中的第一个元素;
2. 当前 窗口外的后一个元素;
2.1 窗口元素的表示
k : 代表窗口的长度, 则下标 [0, k - 1] 代表第一个窗口内的元素 ,所在数组中N的下标。
-
当前窗口外的后一个元素表示:
j:从 k 开始移动, j = k 便是第一个窗口向后移动时,待加入的元素;
j: 代表当前窗口的后面一个元素下标, 即下一次移动窗口时, 该元素应该包含在下一个窗口中, 并且该元素需要被加入到队列中; -
当前窗口的第一个元素表示:
j - k : j = k 时, [j -k ] = [0], 便是第一个窗口中第一个元素, 在数组中的下标为0, 随着j 的增加,以此类推 , j -k 代表的 是后面每个窗口中的第一个元素 在数组中的 下标位置;