Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

Example:

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3
Output: [3,3,5,5,6,7]
Explanation:

Window position Max
--------------- -----
[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

Note: 
You may assume k is always valid, 1 ≤ k ≤ input array's size for non-empty array.

Follow up:
Could you solve it in linear time?

Hint:

  1. How about using a data structure such as deque (double-ended queue)?
  2. The queue size need not be the same as the window’s size.
  3. Remove redundant elements and the queue should store only elements that need to be considered.

这道题给定了一个数组,还给了一个窗口大小k,让我们每次向右滑动一个数字,每次返回窗口内的数字的最大值。难点就在于如何找出滑动窗口内的最大值(这不废话么,求得不就是这个),那么最狂野粗暴的方法就是每次遍历窗口,找最大值呗,OJ 说呵呵哒,no way!我们希望窗口内的数字是有序的,但是每次给新窗口排序又太费时了,所以最好能有一种类似二叉搜索树的结构,可以在 lgn 的时间复杂度内完成插入和删除操作,那么使用 STL 自带的 multiset 就能满足我们的需求,这是一种基于红黑树的数据结构,可以自动对元素进行排序,又允许有重复值,完美契合。所以我们的思路就是,遍历每个数字,即窗口右移,若超过了k,则需要把左边界值删除,这里不能直接删除 nums[i-k],因为集合中可能有重复数字,我们只想删除一个,而 erase 默认是将所有和目标值相同的元素都删掉,所以我们只能提供一个 iterator,代表一个确定的删除位置,先通过 find() 函数找到左边界 nums[i-k] 在集合中的位置,再删除即可。然后将当前数字插入到集合中,此时看若 i >= k-1,说明窗口大小正好是k,就需要将最大值加入结果 res 中,而由于 multiset 是按升序排列的,最大值在最后一个元素,我们可以通过 rbeng() 来取出,参见代码如下:

解法一:

class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
multiset<int> st;
for (int i = ; i < nums.size(); ++i) {
if (i >= k) st.erase(st.find(nums[i - k]));
st.insert(nums[i]);
if (i >= k - ) res.push_back(*st.rbegin());
}
return res;
}
};

我们也可以使用优先队列来做,即最大堆,不过此时我们里面放一个 pair 对儿,由数字和其所在位置组成的,这样我们就可以知道每个数字的位置了,而不用再进行搜索了。在遍历每个数字时,进行 while 循环,假如优先队列中最大的数字此时不在窗口中了,就要移除,判断方法就是将队首元素的 pair 对儿中的 second(位置坐标)跟 i-k 对比,小于等于就移除。然后将当前数字和其位置组成 pair 对儿加入优先队列中。此时看若 i >= k-1,说明窗口大小正好是k,就将最大值加入结果 res 中即可,参见代码如下:

解法二:

class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
priority_queue<pair<int, int>> q;
for (int i = ; i < nums.size(); ++i) {
while (!q.empty() && q.top().second <= i - k) q.pop();
q.push({nums[i], i});
if (i >= k - ) res.push_back(q.top().first);
}
return res;
}
};

题目中的 Follow up 要求我们代码的时间复杂度为 O(n)。提示我们要用双向队列 deque 来解题,并提示我们窗口中只留下有用的值,没用的全移除掉。果然 Hard 的题目我就是不会做,网上看到了别人的解法才明白,解法又巧妙有简洁,膜拜啊。大概思路是用双向队列保存数字的下标,遍历整个数组,如果此时队列的首元素是 i-k 的话,表示此时窗口向右移了一步,则移除队首元素。然后比较队尾元素和将要进来的值,如果小的话就都移除,然后此时我们把队首元素加入结果中即可,参见代码如下:

解法三:

class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
deque<int> q;
for (int i = ; i < nums.size(); ++i) {
if (!q.empty() && q.front() == i - k) q.pop_front();
while (!q.empty() && nums[q.back()] < nums[i]) q.pop_back();
q.push_back(i);
if (i >= k - ) res.push_back(nums[q.front()]);
}
return res;
}
};

类似题目:

Minimum Window Subsequence

Min Stack

Longest Substring with At Most Two Distinct Characters

Paint House II

参考资料:

https://leetcode.com/problems/sliding-window-maximum/

https://leetcode.com/problems/sliding-window-maximum/discuss/65936/My-Java-Solution-Using-PriorityQueue

https://leetcode.com/problems/sliding-window-maximum/discuss/65884/Java-O(n)-solution-using-deque-with-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 239. Sliding Window Maximum 滑动窗口最大值的更多相关文章

  1. [leetcode]239. Sliding Window Maximum滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  2. 239 Sliding Window Maximum 滑动窗口最大值

    给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口 k 内的数字.滑动窗口每次只向右移动一位.例如,给定 nums = [1,3,-1,-3, ...

  3. [LeetCode] Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  4. [leetcode] #239 Sliding Window Maximum (Hard)

    原题链接 题意: 给定一个数组数字,有一个大小为k的滑动窗口,它从数组的最左边移动到最右边.你只能在窗口看到k个数字.每次滑动窗口向右移动一个位置. 记录每一次窗口内的最大值,返回记录的值. 思路: ...

  5. leetcode 239 Sliding Window Maximum

    这题是典型的堆排序算法,只是比一般的堆算法多了删除的操作,有两件事需要做: 1 用一个hash表存储从输入数组索引到堆数组(用于实现堆的那个数组)所以的映射,以便在需要删除一个元素的时候能迅速定位到堆 ...

  6. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. 【LeetCode】239. Sliding Window Maximum

    Sliding Window Maximum   Given an array nums, there is a sliding window of size k which is moving fr ...

  8. 【刷题-LeetCode】239. Sliding Window Maximum

    Sliding Window Maximum Given an array nums, there is a sliding window of size k which is moving from ...

  9. [Leetcode]双项队列解决滑动窗口最大值难题

    这道题是从优先队列的难题里面找到的一个题目.可是解法并不是优先队列,而是双项队列deque 其实只要知道思路,这一道题直接写没有太大的问题.我们看看题 给定一个数组 nums,有一个大小为 k 的滑动 ...

随机推荐

  1. 队列和 BFS —— 栈和 DFS

    队列和 BFS: 广度优先搜索(BFS)的一个常见应用是找出从根结点到目标结点的最短路径. 示例 这里我们提供一个示例来说明如何使用 BFS 来找出根结点 A 和目标结点 G 之间的最短路径. 洞悉 ...

  2. pytorch_13_pytorch 中tensor,numpy,PIL的转换

    PIL:使用Python自带图像处理库读取出来的图片格式numpy:使用Python-opencv库读取出来的图片格式tensor:pytorch中训练时所采取的向量格式 import torch i ...

  3. Flink是如何实现exactly-once语义的

    转自:https://blog.csdn.net/xianpanjia4616/article/details/86375224 最少一次:断了之后 重新执行 再去重 严格一次:根据检查点,再执行一次 ...

  4. paramiko简介

    一.什么是paramiko 要想明白什么是paramiko,要先明白ssh协议. 二.什么是ssh协议 ssh全称是Secure Shell (翻译:安全的外壳),根据字面意思就可以知道是和安全相关的 ...

  5. C# 消息队列之 RabbitMQ 进阶篇

    Ø  简介 在之前的 C# 消息队列之 RabbitMQ 基础入门 中介绍了 RabbitMQ 的基本用法,其实要更全面的掌握 RabbitMQ 这个消息队列服务,我们还需要掌握以下内容: 1.   ...

  6. JVM的监控工具之jconsole

    JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视.管理工具.管理的是什么?管理的是监控信息.永久代的使用信息.类加载等等 如 ...

  7. Zabbix邮件预警-这个坑我跳了不止一次

    文章 Github 地址:点我 每每碰到 Zabbix,我发现配置邮件预警这个坑,我必须要跳进去,跟它是有八辈子的仇哦,哎,接下来数数这些坑.看看你遇到过类似的吗? Zabbix 预警配置流程 监控项 ...

  8. 洛谷 p1541乌龟棋

    洛谷 p1541乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行NN个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第NN格是终点,游戏 ...

  9. Java中关于数据类型的一些问题

    Java中关于数据类型的一些问题 总结一下最近笔试遇到的一些关于Java中数据类型的一些问题. 虽然比较基础,但在实际做题却很容易出错的点,而且往往这些题出错了会给面试官很不好的感觉:你的基础不好. ...

  10. 什么是唯品会JIT业务

    以销定采的模式,供应商将商品发给唯品会仓库在由唯品会发给客户:首先在唯品会创建档期绑定PO此时设置的商品库存为虚拟库存,之后供应商根据实际产生的有效订单将订单中的商品发给唯品会,最后再由唯品会发给用户 ...