leetcode 链接:剑指 Offer 59 - I. 滑动窗口的最大值

题目

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
提示:

你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

示例:

  1. 输入: nums = [1,3,-1,-3,5,3,6,7], k = 3
  2. 输出: [3,3,5,5,6,7]
  3. 解释:
  4. 滑动窗口的位置 最大值
  5. --------------- -----
  6. [1 3 -1] -3 5 3 6 7 3
  7. 1 [3 -1 -3] 5 3 6 7 3
  8. 1 3 [-1 -3 5] 3 6 7 5
  9. 1 3 -1 [-3 5 3] 6 7 5
  10. 1 3 -1 -3 [5 3 6] 7 6
  11. 1 3 -1 -3 5 [3 6 7] 7

解答 & 代码

单调队列(用双端队列实现)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int size = nums.size();
        vector<int> result;        // 结果数组,存储每个滑动窗口的最大值
        if(size == 0 || k <= 0)
            return result;

        // 单调队列(用双端队列实现),存储的是元素下标
        // 队列中从头到尾存储的下标对应的元素值递减,因此队首是最大值的下标
        deque<int> q;

        // 先将前 k 个元素的下标存入队列
        for(int i = 0; i < k; ++i)
        {
            // 如果队尾存的下标对应的值小于等于当前元素,则不断弹出队尾
            // 直到队列为空或队尾存的下标对应的值大于当前元素
            while(!q.empty() && nums[i] >= nums[q.back()])
                q.pop_back();
            // 将当前元素的下标存入队尾
            q.push_back(i);
        }
        // 将第一个滑动窗口(即前k个元素)的最大值(即队首存的下标对应的值)存入结果数组
        result.push_back(nums[q.front()]);

        // 滑动窗口
        for(int i = k; i < size; ++i)
        {
            // 将滑动窗口新的的右边界下标存入单调队列:
            // 如果队尾存的下标对应的值小于等于右边界元素,则不断弹出队尾
            // 直到队列为空或队尾存的下标对应的值大于右边界元素
            while(!q.empty() && nums[i] >= nums[q.back()])
                q.pop_back();
            // 将右边界下标存入队列
            q.push_back(i);

            // 如果队首存的下标小于窗口的左边界,则不断弹出队首
            // 直到队首存的下标在窗口范围内
            while(!q.empty() && q.front() < i - k + 1)
                q.pop_front();
            // 队首存的下标对应的元素就是当前窗口的最大值,存入结果数组
            result.push_back(nums[q.front()]);
        }
        return result;
    }
};

执行结果:

执行结果:通过

执行用时:16 ms, 在所有 C++ 提交中击败了 92.76% 的用户
内存消耗:15.5 MB, 在所有 C++ 提交中击败了 66.49% 的用户