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] 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. [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 ...

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

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

  4. [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 ...

  5. POJ - 2823 Sliding Window (滑动窗口入门)

    An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich is moving from t ...

  6. Sliding Window(滑动窗口)

    Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 58002   Accepted: 16616 Case Time Limi ...

  7. POJ 2823 Sliding Window (滑动窗口的最值问题 )

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 41264   Accepted: 12229 ...

  8. Leetcode: sliding window maximum

    August 7, 2015 周日玩这个算法, 看到Javascript Array模拟Deque, 非常喜欢, 想用C#数组也模拟; 看有什么新的经历. 试了四五种方法, 花时间研究C# Sorte ...

  9. 239. [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 ...

随机推荐

  1. OSGi 基本原理

    定义 OSGi(Open Service Gateway Initiative)技术是面向Java的动态模型系统. 这个框架实现了一个优雅.完整和动态地组价模型.应用程序(称为bundle)无序重新引 ...

  2. 图解使用VS的安装项目打包程序

    背景 这段时间一直在做客户端程序的打包程序,遇到各种坑.因为以前没有任何这方面的经验,历经各种折腾,费尽九牛二虎之力总算是完成了. 虽然没有太多技术含量,但是因为挺繁琐的,所以还是在此记录一下. 由于 ...

  3. AR创意分享:儿童涂鸦遇上程序绘图

    第一节 临摹 小明经常临摹同桌小美的画作. 美术课上,老师表扬了小美的新作. 图1.1 小美的作品<蒙娜·毛虫的微笑> 临,是照着原作画:摹,是用薄纸张蒙在原作上面画. 第二节 借画 小明 ...

  4. Effective前端4:尽可能地使用伪元素

    伪元素是一个好东西,但是很多人都没怎么用,因为他们觉得伪元素太诡异了.其实使用伪元素有很多好处,最大的好处是它可以简化页面的html标签,同时用起来也很方便,善于使用伪元素可以让你的页面更加地简洁优雅 ...

  5. 不到一百行实现一个小siri

    想要容易理解核心的特征计算的话建议先去看看我之前的听歌识曲的文章,传送门:http://www.cnblogs.com/chuxiuhong/p/6063602.html 本文主要是实现了一个简单的命 ...

  6. Angular2 小贴士-多级注入器

    angular2 的依赖注入包含了太多的内容,其中的一个重点就是注入器,而注入器又非常难理解,今天我们不深入介绍注入器的内容,可以参考官方文档,我们今天来说注入器的层级. 也就是组件获取服务的容器会选 ...

  7. px、dp和sp,这些单位有什么区别?

    DP 这个是最常用但也最难理解的尺寸单位.它与“像素密度”密切相关,所以 首先我们解释一下什么是像素密度.假设有一部手机,屏幕的物理尺寸为1.5英寸x2英寸,屏幕分辨率为240x320,则我们可以计算 ...

  8. css3 transition属性

    最近打算学习css3知识,觉得css3写出来的效果好炫好酷,之前一直想要学习来着.可能之前的决心,毅力,耐心不够,所以想要重整起来,放下浮躁的心态,一步一个脚印,踏踏实实的来学习. 首先学习的是css ...

  9. Laravel大型项目系列教程(一)

    Laravel大型项目系列教程(一) 一.课程概述 1.课程介绍 本教程将使用Laravel完成一个多用户的博客系统,大概会包含如下内容: 路由管理. 用户管理,如用户注册.修改信息.锁定用户等. 文 ...

  10. ssl + nginx + tomcat 部署方案

    安装make yum -y install gcc automake autoconf libtool make 安装g++ yum install gcc gcc-c++ 安装PCRE cd /us ...