LeetCode 239.滑动窗口最大值

题目描述

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值 

示例 1:

输入: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

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

思路 

一种错误的思路:考虑使用一个大顶堆来存放窗口里的k个数字,方便知道最大值,但是窗口是移动的,大顶堆无法移除数值,所以不能用。

正确的思路:

使用单调队列来存放窗口里的数字,随着窗口的移动,队列能够进出元素,并更新最大值。队列里的值一定要排序,且最大值要放在出队口。

在设计单调队列的时候,pop,和push操作要保持如下规则:

  1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止

保持如上规则,每次窗口移动的时候,只要deque.front()就可以返回当前窗口的最大值。

代码

C++版:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        // 使用双端队列而不是普通队列,方便实现单调队列
        vector<int> result;
        deque<int> d;
        // 先将前k的元素放进队列
        for(int i=0;i<k;i++){
            // 保证队列前大后小
            while(!d.empty() && nums[i]>d.back()){
                d.pop_back();
            }
            d.push_back(nums[i]);
        }
        result.push_back(d.front());
        // 处理剩余元素
        for(int j=k;j<nums.size();j++){
            // 注意执行顺序
            // 1.移除队首
            if(!d.empty() && nums[j-k]==d.front()){
                d.pop_front();
            }
            // 2.队列末尾插入元素,同时更新最大值
            while(!d.empty() && nums[j]>d.back()){
                d.pop_back();
            }
            d.push_back(nums[j]);
            // 记录对应的最大值
            result.push_back(d.front());
            
            
        }
        return result;
    }
};

Python版:

from collections import deque
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        d = deque() # 需要使用deque实现单调队列,直接使用list会超时
        result = []
        for i in range(k): # 先将前k的元素放进队列
            while d and nums[i]>d[-1]:
                d.pop()
            d.append(nums[i])
        result.append(d[0]) # result记录前k的元素的最大值
        for j in range(k, len(nums)):
            if d and nums[j-k]==d[0]:
                d.popleft()
            while d and nums[j]>d[-1]:
                d.pop()
            d.append(nums[j])
            result.append(d[0])
        return result

需要注意的地方

1.本题的单调队列不需要维护滑动窗口中的所有元素,而是维护有可能成为窗口里最大值的元素就可以了,即保证之前的元素一定不比新加入的元素小,小就弹出,那些小的就是没有必要维护的元素。

2.单调队列的实现并不固定,且可以单独抽象成一个类,总之要保证队列里的元素单调递增或递减。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值