LeetCode 热题 100——子串——滑动窗口最大值
11. 滑动窗口最大值
给你一个整数数组 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 <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
求解
(1)暴力
思路:遍历 + 排序 + push最后一个元素。
var maxSlidingWindow = function(nums, k) {// 判断一些临界值if (nums.length < k) return []let ans = []// 遍历所有滑动窗口for (let i = 0; i < nums.length - k + 1; i++) {let item = nums.slice(i, i + k)item.sort((a, b) => a - b)ans.push(item[k - 1])}return ans
};
复杂度为 O(Nklog(k)):主要有排序
(2)优化
不用排序,复杂度变为:O(Nk)
var maxSlidingWindow = function(nums, k) {// 判断一些临界值if (nums.length < k) return []let ans = []// 遍历所有滑动窗口for (let i = 0; i < nums.length - k + 1; i++) {let max = -Infinityfor (let j = i; j < i + k; j++) {max = Math.max(nums[j], max)}ans.push(max)}return ans
};
但是上面两种方法都超出时间限制。
(3)单调队列
单调队列的核心是维护队列内元素的单调性(这里保持递减),队列头部始终是当前滑动窗口的最大值。
- 入队操作:新元素入队时,从队列尾部开始,移除所有比当前元素小的元素(因为这些元素在当前元素之后,不可能成为后续窗口的最大值),然后将当前元素入队。
- 出队操作:如果队列头部的元素是窗口左边界外的元素(即超出窗口范围),则将其从队列头部移除。
- 获取最大值:队列头部的元素即为当前滑动窗口的最大值。
var maxSlidingWindow = function(nums, k) {// 判断一些临界值if (nums.length < k) return []let ans = []let deque = [] // 队列,递减,deque[0]为最大值for (let i = 0; i < nums.length; i++) {// 判断 左边界有没有超出while(deque.length > 0 && deque[0] < i - k + 1) {deque.shift()}// 删除队列中 比 当前要插入的值 小的while (deque.length > 0 && nums[deque[deque.length - 1]] < nums[i]) {deque.pop()}// 插入当前值deque.push(i)// 判断窗口是否成形if (i >= k - 1) {ans.push(nums[deque[0]])}}return ans
};
方法真的多种多样啊(((φ(◎ロ◎;)φ))),今天先这样吧。
