「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
单调队列
首先单调队列也是队列,是一种维护单调性的队列。单调性分为单调递增和单调递减,因此单调队列也分为单调递增队列和单调递减队列
- 单调递增队列:保证队列头元素一定是当前队列的最小值,用于维护区间的最小值
- 单调递减队列:保证队列头元素一定是当前队列的最大值,用于维护区间的最大值
单调队列适合解决 RMQ(Range Minimum/Maximum Query)问题,即区间最值查询
- 入队操作:队尾入队,会把之前破坏单调性的元素都从队尾移出(维护单调性)
- 出队操作:如果队首元素超出区间范围,将元素从队首出队
- 元素性质:队首元素,永远是当前维护区间的(最大/最小)值
动画演示:单调队列维护滑动窗口最小值
力扣算法题
239. 滑动窗口最大值
分析
- 可以用一个单调递减队列维护区间内的最大值
- 每次滑动窗口,需要将当前元素从队尾入队,在入队前,需要判断当前队列的队尾元素是否小于当前需要入队的元素,如果小于当前元素(破坏了单调递减的性质)就将该元素从队尾出队,直到没有小于当前元素,然后将当前元素入队
- 如果队首元素不在区间内需要从队首出队
- 此时的队首元素就是当前区间的最大值
代码实现
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
var queue = [], ans = []
var n = nums.length
for(var i = 0; i < n; i++) {
var cur = nums[i]
// 将队尾小于需要入队的元素出队,维护单调性
while(queue.length && nums[queue[queue.length - 1]] <= cur) {
queue.pop()
}
// 将当前元素的索引入队
queue.push(i)
// 如果队首元素已经不在活动窗口中则出队
while(i - queue[0] >= k) {
queue.shift()
}
// 当窗口中的元素有K个时输出结果
if(i >= k - 1) ans.push(nums[queue[0]])
}
return ans
};