[LeetCode] 239. Sliding Window Maximum

You are given an array of integers 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 1:

Input: nums = [1,3,-1,-3,5,3,6,7], 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

Example 2:

Input: nums = [1], k = 1
Output: [1]

Example 3:

Input: nums = [1,-1], k = 1
Output: [1,-1]

Example 4:

Input: nums = [9,11], k = 2
Output: [11]

Example 5:

Input: nums = [4,-2], k = 2
Output: [4]

Constraints:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

滑动窗口的最大值。

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

返回滑动窗口中的最大值。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我先介绍一下暴力解。这道题的暴力解是创建一个n + 1 - k长度的数组来存放最后的结果。遍历input数组,在每K个数字里面,通过扫描或者优先队列的方式找到这K个数字中间的最大值,然后放到结果集里面。

时间约等于O(n^2) = O(n + 1 - k) * O(nlogk)

空间O(n)

然而这道题的最优解是用到单调栈(monotonic stack),此处引用并提炼了LC中文网的一个discussion,思路如下

处理前 k 个元素,初始化双向队列。

遍历整个数组。在每一步 :

- 清理双向队列,保持队列里面元素数量不多于K个

- 只保留当前滑动窗口中有的元素的索引

- 当遍历到nums[i]的时候,从队列的尾部开始,移除队列中比当前元素小的所有元素,因为它们不可能是最大的

- 将当前元素nums[i]添加到双向队列中,此时nums[i]应该是队列中最小的元素,同时队列应该是递减的

- 将 deque[0] 添加到输出中

- 返回输出数组

作者:LeetCode
链接:https://leetcode-cn.com/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetcode-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int[] maxSlidingWindow(int[] nums, int k) {
 3         // corner case
 4         if (nums == null || nums.length == 0) {
 5             return new int[0];
 6         }
 7 
 8         // normal case
 9         Deque<Integer> queue = new ArrayDeque<>();
10         // res长度如何计算?可参考一个例子
11         int[] res = new int[nums.length + 1 - k];
12         for (int i = 0; i < nums.length; i++) {
13             // 因为queue存的是下标,所以当queue中有K个元素的时候,就可以开始弹出操作了
14             if (!queue.isEmpty() && queue.peekFirst() == i - k) {
15                 queue.removeFirst();
16             }
17             // 单调递增队列的常规操作
18             while (!queue.isEmpty() && nums[queue.peekLast()] < nums[i]) {
19                 queue.removeLast();
20             }
21             queue.offer(i);
22             // 因为队首元素一定是最大的,所以放他
23             // 在res中下标的查找:当前是i,且对于前K个元素,最大元素都是这个,所以下标是i + 1 - k
24             if (i + 1 >= k) {
25                 res[i + 1 - k] = nums[queue.peekFirst()];
26             }
27         }
28         return res;
29     }
30 }

 

JavaScript实现

 1 /**
 2  * @param {number[]} nums
 3  * @param {number} k
 4  * @return {number[]}
 5  */
 6 var maxSlidingWindow = function (nums, k) {
 7     // corner case
 8     if (nums === null || nums.length === 0) {
 9         return [0];
10     }
11 
12     // normal case
13     let queue = [];
14     let res = new Array(nums.length + 1 - k);
15     for (let i = 0; i < nums.length; i++) {
16         if (queue.length && queue[0] === i - k) {
17             queue.shift();
18         }
19         while (queue.length && nums[queue[queue.length - 1]] < nums[i]) {
20             queue.pop();
21         }
22         queue.push(i);
23         if (i + 1 - k >= 0) {
24             res[i + 1 - k] = nums[queue[0]];
25         }
26     }
27     return res;
28 };

 

单调栈相关题目

LeetCode 题目总结

posted @ 2020-03-10 13:45  CNoodle  阅读(329)  评论(0编辑  收藏  举报