剑指Offer59-Ⅰ.滑动窗口的最大值

  • 题目:剑指Offer59-Ⅰ.滑动窗口的最大值
    输入一个数组nums和一个int k,k表示窗口大小;
    返回一个数组,表示nums从左往右的所有大小为k的窗口中的最大值;
    在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小;

  • 思路:
    若nums长为n,[ 0,k-1 ] 是第一个窗口,[ n - k, n - 1 ]是最后一个窗口,对于每个窗口都要求最大值;
    首先只能遍历窗口的起始位置O(n);
    对于每一个长为k的窗口,要想求最大值:① 暴力遍历当前窗口的所有值,需要O(k)时间 ②如何随着窗口的右移,O(1)求出窗口最大值

1.维护一个单调不严格递减队列deque:O(n):遍历起始位置O(n),对于每个窗口只需O(1)获得最大值,空间O(k):deque最多存当前窗口内的所有元素(当当前窗口内元素不严格单减的时候)

class Solution {
    
    
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    
    
        int n = nums.size();
        if (!n || k > n) return {
    
    };

        vector<int> res;//存每个窗口的最大值
        deque<int> dq;//单调递减队列
        for (int i = 0; i < k; ++i) {
    
    //先把第一个窗口放进去,即以下标0起始的长为k的窗口
            while (!dq.empty() && dq.back() < nums[i]) dq.pop_back();//重复元素留着
            dq.push_back(nums[i]);
        }
        res.push_back(dq.front());//第一个窗口的最大值

        for (int i = 1; i <= n - k; ++i) {
    
    //枚举下标1,2,。。。,n-k为窗口的起始点,并求最大值
            if (nums[i - 1] == dq.front()) dq.pop_front();//窗口右移一步时,最左边少了一个,最右边多了一个
            //维护deque单调递减的性质,把右边新加入窗口的元素放在合适位置,并时刻保持队首为最大值
            while (!dq.empty() && dq.back() < nums[i + k - 1]) dq.pop_back();//这里<而不是<=,意思是重复元素留着,防止如果重复元素为最大值,若刚好退出窗口,pop_front后还留着一个
            dq.push_back(nums[i + k - 1]);                                                       
            
            res.push_back(dq.front());//队首为当前窗口最大值
        }

        return res;
    }
};
  • 总结:
    题解大佬说单调队列的通用写法是存索引,还不会用。。

猜你喜欢

转载自blog.csdn.net/jiuri1005/article/details/114442465