ch6_7 滑动窗口求最大值

如果类中存在__init__ (self), 初始化函数,
则对类建立对象时, 会对该对象先进行初始化函数的调用;

leetcode 239 ,滑动窗口最大值

长度为 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 单调队列的作用与维护

在每一次移动窗口的过程中, 需要对该单调队列进行维护:

  1. 当队列满足条件时, 从队列中移除当前窗口中第一个元素, 以此来代表窗口向后移动了一个元素;
    (满足的条件是: 队列中队首元素 == 当前窗口的第一个元素, 如果队列的首元素, 不等于 当前窗口的第一个元素, 则不移除元素; 为什么只有是首元素,才会移除呢? 因为 单调队列的首元素代表的是最大值, 即 如果当前窗口的首元素恰好是 最大值, 但是现在窗口向后移动了, 它不属于下一个窗口中的数值了, 因此它不能作为下一个窗口中的最大值而存在,应该去除掉;)

  2. 添加窗口外的后一个元素到队列中: 当单调队列满足条件时, 将当前窗口外的后面一个元素加入到队列尾部;
    (单调队列需要满足的条件是: 队列尾部的元素需要大于等于 待存入的元素; 如果当前尾部的元素 小于 待存入元素, 则一直将队尾元素移除, 直到大于等于待存入元素为止 或者 队列中为空 )

  3. 取出当前队列中的最大值, 存入到结果集中, 表明移动窗口后,当前窗口的最大值;


2. 窗口中元素的表示

每次窗口移动时, 窗口的两种元素会与单调队列有关;

  1. 当前窗口中的第一个元素, 需要从队列中移除;
  2. 当前窗口外的后一个元素, 需要加入到队列中;

根据以上两种元素, 来维护更新该队列;

那么问题来了, 如何表示出 上面两种 窗口中的元素;
即移动窗口的过程中, 如何表示出
1. 当前 窗口中的第一个元素;
2. 当前 窗口外的后一个元素;

2.1 窗口元素的表示

k : 代表窗口的长度, 则下标 [0, k - 1] 代表第一个窗口内的元素 ,所在数组中N的下标。

  1. 当前窗口外的后一个元素表示:
    j:从 k 开始移动, j = k 便是第一个窗口向后移动时,待加入的元素;
    j: 代表当前窗口的后面一个元素下标, 即下一次移动窗口时, 该元素应该包含在下一个窗口中, 并且该元素需要被加入到队列中;

  2. 当前窗口的第一个元素表示:
    j - k : j = k 时, [j -k ] = [0], 便是第一个窗口中第一个元素, 在数组中的下标为0, 随着j 的增加,以此类推 , j -k 代表的 是后面每个窗口中的第一个元素 在数组中的 下标位置;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值