本文已参与「新人创作礼」活动,一起开启掘金创作之路。
这里是人不狠话也不多的我,相遇即是缘,面试遇见这类题怎么解决?直接进入正题
这是一道LeetCode原题,原题参考 leetcode.cn/problems/sl…
输入数组:nums
输入窗口大小:k
要求:返回滑动的窗口中的最大值
示例:
nums = [ 1 , 4 , 1 , 5 , 2 , 6 ] k = 3
滑动窗口过程:
[1,4,1] => [4,1,5] => [1,5,2] => [5,2,6]
4 5 5 6
返回 [ 4 , 5 , 5 , 6 ]
优先队列:对于这类求最大值的问题,我们很容易想到优先队列,不明白优先队列是什么的小伙伴也不用担心,这里用简单的文字说明
在本题中,优先队列就好像,一个战斗力高的人,一路上清除战斗力低于自己的人,最终登上巅峰宝座(queue[0] )更是带着一群战斗力不如自己的小弟( queue[1]....queue[n] )。但是最是巅峰留不住,随着时间的流逝( 窗口的滑动 ),宝座上的人要么被时间淘汰;要么就是长江后浪推前浪,终是廉颇老矣,尚能饭否?总会有一个战斗力更高的人将上一任宝座的主人拉下宝座,周而复始。
本题思路:我们创建一个双向队列存储元素下标。保持其长度在 [ 0 , k ]之间,队列单调递减,如果右窗口元素大于队列尾部元素,则依次删除队列尾部小于右窗口的元素,直至队列为空。如果右边窗口元素小于队列尾部元素,则直接加入队列,并且判断队列长度以及队列头部元素是否小于左窗口。
代码
var maxSlidingWindow = function (nums, k) {
//创建一个优先队列,存储元素下标(方便后续下标与左窗口做比较)
let queue = []
let res = []
for (let r = 0; r < nums.length; r++) {
//循环判断,如果右窗口的数字大于优先队列的最小值,则从队尾删除队列元素
while (queue.length && nums[r] >= nums[queue[queue.length - 1]]) {
queue.pop()
}
//将队列中小于右窗口的元素下标清除干净,将r 加入队列
queue.push(r)
//判断队列头部是否在窗口内,如果在窗口外,则从队列头部删除出队,
let l = r - k + 1
if (queue[0] < l) {
queue.shift()
}
当窗口大小为k时,则每一次窗口移动,都会向结果中加入窗口最大值,最大值即是优先队列的queue[0]作为下标在nums中的值
if (r + 1 >= k) {
res.push(nums[queue[0]])
}
}
return res
};