前言 #

看到滑动窗口以及示例,很容易被思维局限了,然后呢就开始打框架,用一个 for 循环,i-i+3 这样的范围一直移动,但是每次都要比较这 3 个值的大小,如何比较呢?用类似之前 T155 的栈一样比较吧。但是存在一个问题,有些值就重复 2-3 次,似乎没有这个必要。

因此,这里我理解了别人的方法,灭掉了自己危险的想法。

解决方案 #

不使用一个 i 了,把它看成一个区间[i,j],也不要 k 个 k 个这样块移动着看。每次移动,i+1,j+1。而比较采用类似 T155 却是双端队列的结构,全部一起来比较,这样每个只会比较 1 次了。

首先来定 i 和 j 的范围,i 是开头,j 是结尾,我们定每次的 j 为索引,给队列添加值,因此 i 就要往前移,去 1-k 的位置。

左边界范围 i ∈ [1 - k, n - k]右边界范围 j ∈ [0, n - 1]

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> d;
        vector<int> maxNums;
        auto n = nums.size();
        for(int i= 1- k,j=0;j<n;i++,j++){
            if (i > 0 && d.front() == nums[i-1]){
                d.pop_front();
            }
            while(!d.empty()&&d.back()<nums[j]){
                d.pop_back();
            }
            d.push_back(nums[j]);
            if(i>=0){
                maxNums.push_back(d.front());
            }
        }
        return maxNums;
    }
};

c++ STL 为我们直接提供了双端队列,我们直接引用。

每次去比较队列最后的值是否比要入列的值小,如果是那就删去,保留比它大的。最大的值永远是队首。

当 i=0 的时候,这个窗口才开始形成了。这时候才可以开始每次移动把队首的值加入数组,组成最大值数组

我们在 i+1 的时候,可能队首的值在移动中被删除了,(是上一个窗口的)那么队列也要做出改变删除,不然无法开始新窗口的比较。

附录双端队列的一些方法

方法 介绍
pop_front 删除第一个元素
front 获取第一个元素
back 获取最后一个元素
pop_back 删除最后一个元素
push_back 向最后添加元素