这是我参与更文挑战的第 2 天,活动详情查看 更文挑战
这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
109. 滑动窗口最大值 (sliding-window-maximum)
标签
- Array
- 滑动窗口
- 困难
题目
这里不贴题了,leetcode打开就行,题目大意:
给你一个整数数组 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]
基本思路
双端队列 就是既可以从队头出队,也可以从队尾出队的队列。
为什么要使用双端队列,怎么思考出用双端队列这个方法,我之后会来补充我的思考,因为现在我还无法准确表达,不乱说。
写法实现
var maxSlidingWindow = function(nums, k) {
// windowIdxArr 顾名思义存 窗口中的下标位置,res 存最终结果
let [windowIdxArr, res] = [[], []]
for (let i = 0; i < nums.length; i++) {
// 当下标的间距范围超出了 k 就把窗口最左边的元素(windowIdxArr[0] = 0)出队
// [1 3 -1 -3] 5 3 6 7 比如这样 遍历到 -3 (i = 3)了那么 windowIdxArr[0] === i - k
// 就要把第一个位置下标0从 windowIdxArr 队头出队 => 1 [3 -1 -3] 5 3 6 7
if (i >= k && windowIdxArr[0] <= i - k) {
// ---> [关键(1)]
windowIdxArr.shift()
}
// 重点就是这里 向前依次比较队尾的元素,比他小的从从队尾出, 让队列坐标对应元素单调减
while (windowIdxArr.length && nums[windowIdxArr.slice(-1)] <= nums[i]) {
// ---> [关键(2)]
windowIdxArr.pop()
}
// 清除完不符合大小条件的元素后,新加入的元素进入窗口
// ---> [关键(3)]
windowIdxArr.push(i)
// 把本轮窗口中最大的进结果数组
// 注意至少得3个元素,下标从0开始
if (i >= k - 1) {
// ---> [关键(4)]
// 因为队列元素是单调减的,本轮最大就是 idx 的第一个对应元素
res.push(nums[windowIdxArr[0]])
}
}
return res
};
let nums = [1,3,-1,-3,5,3,6,7], k = 3
console.log(maxSlidingWindow(nums, k))
我们跟随代码看下面解析,关键在 [1]/[2]/[3]/[4]
这几个地方
滑动窗口的位置 本轮最大值 res[i 轮最大 idx]
--------------- -----
[1 3 -1] -3 5 3 6 7 3
i = 0
, 只会执行关键(3)
(其他都不满足) 当前 windowIdxArr (下面简称index 队列
)为 [0]i = 1
, 此时我们发现关键(2)
条件满足,(3 大于 队尾元素 1),那么把队尾元素出队,index 队列
为 [], 然后在 把当前 3的下标 1 入队 当前index 队列
为 [1],此时 (i(1) < (k长(3) - 1) = 2) 还没到 k 的长度,所以 res 还不需要推入i = 2
, 满足[3],入队index 队列
为 [1, 2], 满足[4],入结果数组 [3]- ... 后面依次类推
最核心思想是下面代码关键(2)处: 解释下,当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。为了保持队列的性质,我们会不断地将新的元素与队尾的元素相比较
,如果前者大于等于后者,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。这样保证了,队列中下标对应的元素是严格单调递减的
,因此此时队首下标对应的元素就是本轮滑动窗口中的最大值。
另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列
今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友
Or 搜索我的微信号infinity_9368
,可以聊天说地
加我暗号 "天王盖地虎" 下一句的英文
,验证消息请发给我
presious tower shock the rever monster
,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧