剑指offer:Python 滑动窗口的最大值 图解详细过程,绝对让你看懂!Leetcode 滑动窗口的最大值

题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

思路及Python实现

  • 我们先创建一个双端队列queue来保存传入数字(num)的索引,创建一个res来保存,每次的最大值,遍历num来取到每一个值得索引!详细过程如下图解
  • index=0 ,只有一个元素和索引,直接添加到queue中
    在这里插入图片描述
  • index=1 所指向的值3 大于前面的2 让它对应的索引0 从queue中出列,将索引index=1添加到队列
    在这里插入图片描述
  • index=2 值为4,大于前面的3 让它的索引出列;然后添加当前索引 2 ,同时索引长度已经=3,即索引:0 1 2 已经有size=3 的长度了,第一个窗口已经形成,将其中最大的值放到res中,即是 4
    在这里插入图片描述
  • index=3 对应值为2 ;直接将索引添加到队列,目前最大还是4,再添加到res
    在这里插入图片描述
  • index=4 对应值为6,它的值大于前面的2 ,弹出队列中前一个索引3,还没结束哦,继续它还大于索引2对应的值,再弹出它;将index=4添加到队列,此时最大为6,添加到res
    在这里插入图片描述
  • index=5,对应2,不大于6,将索引添加到queue,同时res再获得一次6
    在这里插入图片描述
  • index=6 值为5,大于前一个索引的值,所以前一个索引从队列中弹出;添加当前索引,res记录当前最大的值,再添加一个6
    在这里插入图片描述
  • index=7 ,此时队列前一个索引为4(看上图,下图是完成此步后的模样)长度为3,所以窗口滑动,移出了数值6的位置,此时数值5是最大了,res添加一个5
    在这里插入图片描述
  • 整体思想就是,记录每一次的索引,如果当前索引对应的值大于前一个值的话,前面所有的索引都从队列中弹出;如果当前索引的值小于前一个索引对应的值,添加当前索引(反正我们返回的是最大的值,如果一直有小的值加入的话,前面的大值就会被滑动掉),注意下窗口大小,就ok了
  • 总之就是要多画图,多画图,就非常好理解了!
class Solution:
    def maxInWindows(self, num, size):
        # 双端队列维护从大到小元素的索引
        # 每遇到一个元素,从后往前将队列中小于该元素的索引全部弹出
        # (因为在滑动窗口长度内,小于该元素的值不可能成为最大值,1是该元素在他们后面,2是该元素值比他们大)
        if size > len(num) or size < 1:
            return []
        from collections import deque  # 导入一个双端队列
        queue = deque()
        res = []
        for index, val in enumerate(num): # 枚举,循环
            if index == 0: # 队列为空时加入第一个元素
                queue.append(index)
            else:
                # 判断队首是否滑出了窗口
                if index - queue[0] == size:
                    queue.popleft()
                # 为当前元素在队列中找到相应位置,其后所有元素弹出
                while queue and num[index] >= num[queue[-1]]:
                    queue.pop()
                queue.append(index)
                # print(queue)
            # 当滑动窗口大小==size时,可以开始记录最大值
            if index >= size - 1:
                res.append(num[queue[0]])
        return res

用普通的队列和循环完成

class Solution:
    def maxInWindows(self, num, size):
        queue = []
        res = []
        n = len(num)
        if n == 0 or n < size or size == 0:
            return res
        for i in range(n):
            if len(queue) != 0 and i - size >= queue[0]:
                # 判断队首元素是否已经在窗口之外了,如果是,队首元素出队
                queue.pop(0)
            while queue and num[i] >= num[queue[-1]]:
                # 运行到这一步,队列里的元素,其对应的num中的数,都在这个滑动窗口里的
                # 因此,如果num后面的数比前面的数大,那么前边的数,就不可能在成为最大值了,
                # 因为窗口是往右移动的,只要在窗口的范围内,包含前面的数,就一定包含后面的数,
                # 但是包含后面的数,不一定包含前面的数。
                # 因此要将在队列中的,比num[i]小的num前面的数的下标出队。
                # 因为他不可能成为最大值了。
                queue.pop()
            queue.append(i)
            # i入队,如果队列中存在的元素对应的数都比num[i]大,将i入队就行,
            # 因为当前边的元素都不在窗口内时,num[i]可能是窗口内元素的最大值。
            if queue and i >= size - 1:
                # 因为窗口的长度是size,所以前size-1个元素不进行处理
                res.append(num[queue[0]])
                # 因为上一个循环,队首元素对应的数一定是最大的。
                # 将队首对应的元素压入结果中,这一步元素不出队,
                # 因为队首元素不一定是窗口的左边界,下一次移动窗口,
                # 队首元素还可能在窗口中,而且是最大的。
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值