滑动窗口的最大值:最直观的想法是,两层for循环,外层i表示每次窗口的起始位置,内层j表示每次窗口的结束位置,遍历窗口内的每一个元素,然后取窗口内的最大值,并加入到结果数组中。注意,当数组为空时或者滑动窗口值大于数组长度,要返回空数组。(牛客这个暴力方法居然过啦)

vector<int> maxInWindows(const vector<int>& num, unsigned int size) 
{
     vector<int> res;
     // 数组为空 或者 滑动窗口值大于数组长度
     if(num.size()==0||size>num.size())
        return res;
     int maxn;
     // i表示起始位置
     for(int i=0;i+size-1<num.size();i++)
     {
         maxn=num[i];
         // j表示结束位置 遍历整个窗口
         for(int j=i+1;j<=i+size-1;j++)
         {
            maxn=max(num[j],maxn);
         }
         // 将最大值加入结果
         res.push_back(maxn);
     }
     return res;
}

优化:上述方法其实包含很多重复计算,我们可以通过分析来优化。如果当前元素大于前面元素,那么前面的元素不可能成为最大值,故需要将前面的元素从队尾出队;如果当前元素小于等于前面元素,那么需要将元素从队尾入队,因为该元素可能会成为后续的最大值。同时,我们要判断窗口内元素是否过期,即队头元素下标是否小于当前窗口左端,由于要方便统计窗口边界,故使用的是下标存储,当超过边界不合法时需要从队头出队;最后要判断当前元素下标是否满足一个窗口长度,因为只有有窗口才可以将当前窗口内的最大值加入结果数组。注意,使用的是双端队列!这样就维护了一个长度为size的单调递减队列,每次都从队头取窗口内的最大值!

vector<int> maxInWindows(const vector<int>& num, unsigned int size) 
{
     vector<int> res;
     // 数组为空 或者 滑动窗口值大于数组长度
     if(num.size()==0||size>num.size())
        return res;
     // 双端队列
     deque<int> dq;
     for(int i=0;i<num.size();i++)
     {
        // 如果当前元素大于之前的 则将之前的元素依次从队尾弹出 从而保证维护的是单调递减队列
        while(!dq.empty()&&num[i]>num[dq.back()])
           dq.pop_back();
        // 将元素下标入队 以便后续判断元素是否在窗口内
        dq.push_back(i);
        // 若队头元素不合法就从队头弹出 双端队列维持长度为size 队首小于窗口左端则过期
        if(i-dq.front()+1>size)
           dq.pop_front();
        // 当满足窗口长度时就将窗口最大值加入结果数组
        if(i>=size-1)
           res.push_back(num[dq.front()]);
     }
     return res;
}