滑动窗口的模板:

let left = 0, right = 0;
 
while (right < s.size()) {`
    // 增大窗口
    window.add(s[right]);
    right++;
    while (window needs shrink) {
        // 缩小窗口
        window.remove(s[left]);
        left++;
    }
}

我认为滑动窗口的关键点在于移动右指针时的各种操作,以及左指针进行右移的判断条件。

剑指 Offer 59 - I. 滑动窗口的最大值

该题需要实现动态更新滑动窗口中三个数的最大值,问题关键是在右移时,前一个窗口的状态记录的最大值可以正好为左边界,在更新窗口后,这个值就不存在,需要再次进行三个值的max判断,时间复杂度的原因不会ac。

因此,需要使用一个方式,来动态进行滑动窗口中最大值的存储:单项队列。

Java 分布式集群滑动窗口计数法_Java 分布式集群滑动窗口计数法

图片转自LeetCode

我们定义一个deque单项队列,该队列必须严格的单调递减,实现方法是每次添加元素时,判断末尾元素是否小于新添加的元素,小于则一直进行pop,直到不符合条件后则添加进去。

首先初始化窗口左右边界以及队列。得到第一个结果,添加到res数组中

之后进行滑动窗口的状态更新,while的条件应为右指针大于数组的大小。

 初始时由于窗口已经增大左边界需要右移,判断队列当中的头元素是否与左边界相当,相等的话需要弹出队列,之后再进行左边界右移。

每次右边界改变时,都必须循环进行一次递减队列的判断,确保队列的头元素为最大的值,之后添加最大值到res,然后右边界再加1

code:

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function(nums, k) {
    if (!nums.length)return [];
    var left=0,right=0,deque=[],res=[];
    while(right<k){
        while(deque.length && deque[deque.length-1]<nums[right]){
            deque.pop();
        }
        deque.push(nums[right]);
        right+=1;
    }
    res.push(deque[0]);
    while(right<nums.length){
        if(nums[left]==deque[0])deque.shift();
        left+=1;
        while(deque.length && deque[deque.length-1]<nums[right]){
            deque.pop();
        }
        deque.push(nums[right]);
        res.push(deque[0]);
        right+=1;
    }
    return res;
};

该题可以看出来困难难度其实思路很简单,重要的是掌握做题的方法以及对算法使用的技巧。

剑指 Offer 59 - II. 队列的最大值

该题要求求队列最大值的时间复杂度均摊为1,因此可以考虑使用一个辅助的单向队列来实现。

每次在添加队列的时候先对主队列进行添加,然后需要对辅助队列进行一个单向的维护。

使用while来从末尾开始pop每一个比新添加值小的元素(while的条件为辅助队列不为空且末尾元素小于新添加值),之后再添加进去、

每次在弹出队列的时候对辅助队列的第一个元素进行判断,如果两个元素的值相等则同时弹出。

var MaxQueue = function() {
    this.dq = [];
    this.max_dq = [];
};

/**
 * @return {number}
 */
MaxQueue.prototype.max_value = function() {
    if(this.max_dq.length){
        return this.max_dq[0];
    }
    else return -1;
};

/** 
 * @param {number} value
 * @return {void}
 */
MaxQueue.prototype.push_back = function(value) {
    this.dq.push(value);
    while(this.max_dq.length && this.max_dq[this.max_dq.length-1]<value){
        this.max_dq.pop();
    }
    this.max_dq.push(value);
};

/**
 * @return {number}
 */
MaxQueue.prototype.pop_front = function() {
    if(this.dq.length){
        if(this.dq[0] == this.max_dq[0]){
            this.max_dq.shift();
        }
        var temp = this.dq[0];
        this.dq.shift();
        return temp;
    }
    else return -1;
};

/**
 * Your MaxQueue object will be instantiated and called as such:
 * var obj = new MaxQueue()
 * var param_1 = obj.max_value()
 * obj.push_back(value)
 * var param_3 = obj.pop_front()
 */