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

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

难度: h a r d \color{red}{hard} hard


题目描述

给定一个数组 n u m s nums nums 和滑动窗口的大小 k k k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[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

提示:

你可以假设 k 总是有效的,在输入数组 不为空 的情况下, 1 ≤ k ≤ n u m s . l e n g t h 1 ≤ k ≤ nums.length 1knums.length

注意:本题与主站 239 题相同:https://leetcode-cn.com/problems/sliding-window-maximum/


算法

(单调队列)

使用 单调栈 实现了随意入栈、出栈情况下的 O ( 1 ) O(1) O(1) 时间获取 “栈内最小值” 。 “出栈操作” 删除的是 “列表尾部元素” ,而 “窗口滑动” 删除的是 “列表首部元素” 。

窗口对应的数据结构为 双端队列 ,本题使用 单调队列 即可解决以上问题。遍历数组时,每轮保证单调队列 deque

  • deque 内 仅包含窗口内的元素 ⇒ 每轮窗口滑动移除了元素 nums[i−1] ,需将 deque 内的对应元素一起删除。
  • deque 内的元素 非严格递减 ⇒ 每轮窗口滑动添加了元素 nums[j+1] ,需将 deque 内所有

算法流程:

  • 初始化: 双端队列 deque ,结果列表 res ,数组长度 n ;

  • 滑动窗口: 左边界范围 i∈[1−k,n−k] ,右边界范围 j∈[0,n−1] ;

    • 若 i>0 且 队首元素 deque[0] = 被删除元素 nums[i−1] :则队首元素出队;
    • 删除 deque 内所有
    • 将 nums[j] 添加至 deque 尾部;
    • 若已形成窗口(即 i≥0 ):将窗口最大值(即队首元素 deque[0] )添加至列表 res ;
  • 返回值: 返回结果列表 res ;

复杂度分析

  • 时间复杂度 O ( n ) O(n) O(n)

  • 空间复杂度 : O ( k ) O(k) O(k)

C++ 代码

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        deque<int> q;
        for (int i = 0; i < nums.size(); i ++)
        {   
            // 如何下一个数比最小的数还大,说明队列中的数值一定不是最大值,那么就弹出队列中的末尾元素
            while (q.size() && nums[i] > q.back()) q.pop_back();
            q.push_back(nums[i]);

            // 判断往后移动一位的时候,当前需要弹出的值是不是队列中的队头元素,如果是就弹出
            if (i >= k && nums[i - k] == q.front()) q.pop_front();
            // 判断是否形成队列,如果是就把队头元素加入答案
            if (i >= k - 1) res.push_back(q.front());
        }

        return res;
    }
};

你可能感兴趣的:(剑指,Offer(第,2,版),链表,数据结构)