239. Sliding Window Maximum

problem description

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

Example:

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3 Output: [3,3,5,5,6,7] Explanation:

Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
Note: 
You may assume k is always valid, 1 ≤ k ≤ input array's size for non-empty array.

Follow up: Could you solve it in linear time?

algorithm thought

经典的滑动窗口问题。如果最暴力的方法就是每移动一步,循环判断所有的数字,找到最大值。但是这样做的话,时间复杂度就是O(nk),还是需要挺久时间的。

由于前一次查找到的最大值过程中,很多信息对后一次来说肯定也是能用上的。所以需要想个办法利用之前的信息。

首先需要知道的一点是,如果当前来了个很大的值,那么还在窗口中的,之前的比这个值小的值就已经失去作用了。之后肯定不会被放入结果。那么我们就在每次加入新数的时候,将之前比它小的数剔除,然后将当前值插入。这样就能保证当前最后一个数就是最大值了。还需要注意的一个点是,当窗口中的数大于k的时候,需要剔除最后一个数。

现在,另一个重要的问题就是,根据上面提出的需求,选取合适的数据结构来解题。在上面的需求中,我们既要操作尾端(剔除最后一个数),也要操作首端(加入新数的时候,剔除比他小的数)。这两个操作都是线性时间的数据结构有链表和双端队列。这里我们用双端队列实现

code

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

algorithm analysis

这里需要用平均情况去分析。对于每一个数,都只进行了一个入队和出队操作,所以,平均时间复杂度是O(n)

Last updated