59-01 滑动窗口的最大值

题目

给定一个数组和滑动窗口的大小,请找出所有滑动窗口的最大值。例如,输入数组{2,3,4,2,6,2,5,1}和数字3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}。

牛客网 OJ
AcWing OJ

C++题解

借助双向队列,对于新来的元素k,将其与队列中元素比较:

  • 若队列中有元素比k小,直接将之前比k小的元素移除队列(因为不可能再成为后面滑动窗口的最大值),压入k。
  • 若队列中元素x比k大,则根据下标检测x是否在窗口内,如果不在则移除队列,压入k。

注意:

  • 队列的第一个元素是滑动窗口的最大值;
  • 队列存放的是数字在数组中的下标,而不是数值。

举例说明:

1、将2压入队列
2、3比2大,弹出2,压入3
3、4比3大,弹出3,压入4
4、2比4小,4还在窗口内,保留4,压入2
5、6比4和2都大,因此弹出4和2,压入6
6、2比6小,6在窗口内,保留6,压入2
7、5比2大,比6小,且6还在窗口内,弹出2,压入5
8、1比6和5都小,但是6不在窗口内,6弹出,压入1
class Solution {
public:
    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        vector<int> res;
        deque<int> data;
        
        for (unsigned  int i = 0;i < num.size();i++)
        {
            // 如果辅助队列非空,并且队尾的元素小于当前的值,那么就将队尾的元素出队
            // 因为它小于当前的值,所以它不可能有机会成为最大值
            while(data.size() && num[data.back()] <= num[i])
                data.pop_back();
            
            // 如果当前的队首元素的位置已经超过了滑窗大小,那么应该将其从队首移出
            while(data.size() && i - data.front() + 1 > size)
                data.pop_front();
            
            // 每次都将当前的值添加到队尾中
            data.push_back(i);
            
            // 滑窗大于0并且已经满足滑窗范围,那么就将当前的队首元素添加到结果中
            if(size && i + 1 >= size)
                res.push_back(num[data.front()]);               
        }   
        
        return res;
    }
};

python题解

思路与C++题解一致。

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        
        listA = []
        res = []
        
        for i in range(len(num)):
            while listA and num[listA[-1]] <= num[i]:
                listA.pop()
            
            while listA and (i - listA[0] + 1) > size:
                listA.pop(0)
            
            listA.append(i)
            
            if size and i + 1 >= size:
                res.append(num[listA[0]])
        
        return res

注意:

  • python中 list 的pop()函数可以根据索引移除值,而默认的索引是-1,不要理解为只能移除最后一个值。
posted @ 2019-03-17 17:33  youngliu91  阅读(223)  评论(0)    收藏  举报