微信公众号:路人zhang
扫码关注微信公众号

回复“面试手册”,获取本站PDF版

回复“简历”,获取高质量简历模板

回复“加群”,加入程序员交流群

回复“电子书”,获取程序员类电子书

当前位置: 算法 > 剑指offer > 剑指offer 59-1. 滑动窗口的最大值

题目描述

给定一个数组 nums 和滑动窗口的大小 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 ≤ 输入数组的大小。


题解

(单调队列) O(n)

使用单调队列求解滑动窗口中的最大值,单调队列可以用双端队列来实现,队头和队尾都可以压入和弹出元素,单调队列中存储的是元素的下标,其中队头是整个队列的最大元素的下标,从队头到队尾下标代表的元素值依次递减,这就是单调队列。

  1. 遍历数组,初始状态单调队列为空,再遍历的过程中,每次插入元素前,需要判断: (1) 合法性检查:队头是否已经出队,如果当前元素的下标 i 到队头的距离大于等于 k,则队头应该出队,它已经不在当前窗口内了。 (2) 单调性维护:如果当前元素 nums[i] 大于等于队尾元素下标对应的值,那么队尾元素就再也不可能成为某个滑动窗口的最大值了,所以将满足条件的队尾都出队,始终保持队列中下标对应的元素值从队头到队尾是单调递减的。
  2. 插入当前元素的下标 i
  3. 当窗口中填满了数字时开始记录答案,队头下标对应的元素值就是窗口内的最大值。

时间复杂度

遍历数组的过程中,每个元素下标最多进队一次出队一次,所以时间复杂度为 O(n)。

空间复杂度

存储单调队列需要额外 O(k) 的空间,存储答案需要额外 O(n) 的空间。

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 ++ ) {
            if (q.size() && i - q.front() >= k) q.pop_front();
            while (q.size() && nums[q.back()] < nums[i]) q.pop_back();
            q.push_back(i);

            if (i >= k - 1) res.push_back(nums[q.front()]);
        }
        return res;
    }
};

Java 代码

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        Deque<Integer> q = new LinkedList<>();
        for (int i = 0; i < nums.length; i ++ ) {
            if (!q.isEmpty() && i - q.getFirst() >= k) {
                q.removeFirst();
            }
            while (!q.isEmpty() && nums[q.getLast()] < nums[i]) {
                q.removeLast();
            }
            q.addLast(i);

            if (i >= k - 1) {
                res.add(nums[q.getFirst()]);
            }
        }

        return res.stream().mapToInt(Integer::intValue).toArray();
    }
}

Python 代码

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        res = []
        q = deque()
        for i in range(len(nums)):
            if q and i - q[0] >= k:
                q.popleft()
            while q and nums[q[-1]] < nums[i]:
                q.pop()
            q.append(i)

            if i >= k - 1:
                res.append(nums[q[0]])
        return res

本文由读者提供Github地址:https://github.com/tonngw


点击面试手册,获取本站面试手册PDF完整版