[路飞]_滑动窗口最大值

248 阅读1分钟

「这是我参与2022首次更文挑战的第40天,活动详情查看:2022首次更文挑战

leetcode-239 滑动窗口最大值

题目介绍

原题目请见上方链接

解题思路

这道题很容易想到的做法是先取前 k 个数字,然后获取这 k 个数字中的最大值,插入到结果数组中,然后再往后移动一位,再次获取 k 个数字中的最大值,一直到遍历完整个数组,但是这样需要执行 nums.length - k + 1 次比较 k 个数的大小,并且前后两次比较之间其实只有一个数是不同的,这样的效率太低

接下来我们利用队列的思想来看一下下面的这种做法:

  1. 定义一个双端队列 queue,用于存放滑动窗口中的数在 nums 中的下标
  2. 依次遍历数组 nums 中的每个值
  3. 当队尾元素指向的值小于即将入队的值时,将队尾元素从队尾弹出
  4. 重复步骤 3,直到队列为空或者队尾元素指向的值大于即将入队的值
  5. 将即将入队的值的下标入队
  6. 判断队首的元素下标是否应该在当前的滑动窗口中,即 队首的下标 + k <= 新入队的下标 i 则表示队首的下标已经不在当前的滑动窗口中,应该将当前下标从队列中出队
  7. 此时在队列中队首存放的下标即为当前窗口最大值的下标,因为从开始遍历到第 k 个值之后才需要输出窗口的最大值,因此还需要将当前入队的下标与 k 值作比较,符合条件的才将队首存放下标指向的值插入到结果数组中

演示文稿 4(1).gif

解题代码

var maxSlidingWindow = function(nums, k) {
    const ans = []
    const queue = []
    let i = 0
    while (i < nums.length) {
        while (queue.length && nums[queue[queue.length - 1]] <= nums[i]) {
            queue.pop()
        }
        queue.push(i)
        if (queue.length && queue[0] + k <= i) {
            queue.shift()
        }
        i++
        if (i >= k) ans.push(nums[queue[0]])
    }
    return ans
};