239. 滑动窗口最大值

https://leetcode-cn.com/problems/sliding-window-maximum/

题目描述

方法 1:暴力法(TLE)

思路

直觉想法,当然是在滑动窗口每次滑动时都遍历窗口找到最大值,果不其然超时了 ╮(╯_╰)╭

49 / 59 个通过测试用例

复杂度分析

  • 时间复杂度:$O((N-k)*k)$,N 是数组长度。

  • 空间复杂度:$O(1)$。

代码

JavaScript Code

方法 2:大顶堆(TLE)

思路

要找最大值,自然而然就能想到堆了。

但如果直接每个滑动窗口都建一个堆的话,

  • 时间复杂度是 $O(klogk*(N-k))$:

    • 其中建堆的时间是 $O(klogk)$。

    • 一共有 $N-k+1$ 个滑动窗口。

  • 空间复杂度是 $O(k)$,堆的大小。

这样时间复杂度还是太高了,会超时(49 / 59 个通过测试用例)。

优化

我们要记住固定长度滑动窗口的特点,就是 每次滑动变动的只有头尾两个元素

如果我们能在窗口滑动时用新元素替换旧元素,再对堆进行 heapify 操作,这样时间复杂度就变成了:

  • 建堆时间复杂度是 $O(klogk)$。

  • 滑动窗口滑动时,替换元素的时间是 $O(k+logk)$,

    • 其中找到旧元素的时间是 $O(k)$

    • heapify 的时间是 $O(logk)$

  • 一共有 $N-k+1$ 个滑动窗口,所以总的时间复杂度是 $O(klogk + (N-k)(logk + k))$

  • 也就是 $O(N*k)$ 吧 (⓿_⓿) 大概可以这样约掉...忽略掉其中较小的数

原以为能 AC 的,大意了,还是 TLE。

JavaScript: 52 / 59 个通过测试用例 Python: 49 / 59 个通过测试用例

复杂度分析

  • 时间复杂度:$O(N*k)$。

  • 空间复杂度:$O(k)$。

代码

Python Code

JavaScript Code

方法 3:平衡二叉搜索树

思路

  • 滑动窗口的大小是 k,我们要找出 k 个数字中的最大值。

  • 窗口每次滑动时变化的只有头尾两个数字。

基于以上两点,我们可以考虑用一个数据结构来存这 k 个数字,每次窗口滑动时,用 nums[r+1] 替换掉 nums[l],然后再返回 k 个数字中的最大值。

因此我们需要的是一个可以快速找到 nums[l],还能快速找到最大值,也就是,能 快速查找值 的数据结构。就是你啦!二叉搜索树!

不过,二叉搜索树有可能会退化成链表,搜索时间变成 $O(N)$,而平衡二叉搜索树,也就是 AVL 树,作为升级版的二叉搜索树,它的搜索时间永远是 $O(logN)$,所以我们可以用 AVL 树。

由于我还没有写过 AVL 树,这里就偷懒不写啦。(。_。) 不知道会不会超时。

复杂度分析

  • 时间复杂度:$O((N-k)*logk)$,N 是数组长度,一共有 $N-k+1$ 个滑动窗口,$logk$ 是向 AVL 树插入和查询值的时间。

  • 空间复杂度:$O(k)$,AVL 树的大小。

代码(TODO)

JavaScript Code

方法 4:deque

思路

直觉解法全都超时了,看来虽然题目说进阶是线性时间,但我看它根本就是要求线性时间!

题目给了提示说可以用 deque。没力气写太多,直接看代码注释吧 ( ╯□╰ )。

复杂度分析

  • 时间复杂度:$O(N)$,N 是数组长度,每个数字最多入列出列一次。

  • 空间复杂度:$O(k)$,deque 的空间。

代码

JavaScript Code

单调队列 @feiker

JavaScript Code

Last updated

Was this helpful?