力扣题目链接[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(kn) ,近乎于O(n^2) ,时间复杂度太高,因此不考虑。
我们要合理利用每次窗口变化时最大值的更替。只要当前最大值没有出界,并且新加入的元素不大于最大值,此时就不需要更换最大值。直到最大值出界或者新加入的元素大于最大值,就更换第二大元素为最大值。
本题的难点在于:如何在每次窗口滑动后,将 “获取窗口内最大值” 的时间复杂度从O(k)降低至 O(1)。
首先上最终代码:
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
if (!nums.length || !k) return []; // 参数为空数组或者k为0就返回空数组
let deque = []; // 初始化辅助队列
let length = nums.length; // 缓存数组长度
let res = Array.from({ length: length - k + 1 }); // 初始化指定长度的结果数组
for (let j = 0, i = 1 - k; j < length; i++, j++) {
if (i > 0 && deque[0] === nums[i - 1]) deque.shift();
while(deque.length && deque[deque.length - 1] < nums[j]) {
deque.pop();
}
deque.push(nums[j]);
if (i >= 0) res[i] = deque[0];
}
return res;
};
分析:
我们采用辅助队列来降低时间复杂度。具体做法为:
最终返回结果数组即可。
本题通过辅助递减队列来存储滑动窗口中的最大值。如果题目更改为最小值,求解思路也是类似的。
复杂度方面,需要遍历整个数组,因此时间复杂度是O(n) ,队列大小为k,因此空间复杂度是O(k) 。
[1]
力扣题目链接: https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/58o46i/