From 9de0985e341a765d6970a263f451532606495b53 Mon Sep 17 00:00:00 2001 From: lucifer Date: Mon, 30 Nov 2020 11:16:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=A2=9D=E5=A4=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/239.sliding-window-maximum.md | 29 +++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/problems/239.sliding-window-maximum.md b/problems/239.sliding-window-maximum.md index 2d9c5cf23..bf1f1b634 100644 --- a/problems/239.sliding-window-maximum.md +++ b/problems/239.sliding-window-maximum.md @@ -56,7 +56,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/ ## 思路 符合直觉的想法是直接遍历 nums, 然后然后用一个变量 slideWindow 去承载 k 个元素, -然后对 slideWindow 求最大值,这是可以的,时间复杂度是 O(n \* k).代码如下: +然后对 slideWindow 求最大值,这是可以的,遍历一次的时间复杂度是 $N$,k 个元素求最大值时间复杂度是 $k$, 因此总的时间复杂度是 O(n \* k).代码如下: JavaScript: @@ -90,10 +90,20 @@ class Solution: ``` 但是如果真的是这样,这道题也不会是 hard 吧?这道题有一个 follow up,要求你用线性的时间去完成。 -我们可以用双端队列来完成,思路是用一个双端队列来保存`接下来的滑动窗口可能成为最大值的数`。具体做法: -- 入队列 +其实,我们没必须存储窗口内的所有元素。 如果新进入的元素比前面的大,那么前面的元素就不再有利用价值,可以直接移除。这提示我们使用一个[单调递增栈](../thinkings/monotone-stack.md "单调栈专题")来完成。 + +但由于窗口每次向右移动的时候,位于窗口最左侧的元素是需要被擦除的,而栈只能在一端进行操作。 + +而如果你使用数组实现,就是可以在另一端操作了,但是时间复杂度仍然是 $O(k)$,和上面的暴力算法时间复杂度一样。 + +因此,我们考虑使用链表来实现,维护两个指针分别指向头部和尾部即可,这样做的时间复杂度是 $O(1)$,这就是双端队列。 + +因此思路就是用一个双端队列来保存`接下来的滑动窗口可能成为最大值的数`。 + +具体做法: +- 入队列 - 移除失效元素,失效元素有两种 1. 一种是已经超出窗口范围了,比如我遍历到第 4 个元素,k = 3,那么 i = 0 的元素就不应该出现在双端队列中了 @@ -101,7 +111,7 @@ class Solution: 2. 小于当前元素都没有利用价值了,具体就是`从后往前遍历(双端队列是一个递减队列)双端队列,如果小于当前元素就出队列` -如果你仔细观察的话,发现双端队列其实是一个递减的一个队列。因此队首的元素一定是最大的。用图来表示就是: +经过上面的分析,不难知道双端队列其实是一个递减的一个队列,因此队首的元素一定是最大的。用图来表示就是: ![](https://tva1.sinaimg.cn/large/007S8ZIlly1ghltxg29buj30hb0di757.jpg) @@ -115,6 +125,8 @@ class Solution: JavaScript: +JS 的 deque 实现我这里没有写, 大家可以参考 [collections/deque](https://github.com/montagejs/collections/blob/master/deque.js) + ```js var maxSlidingWindow = function (nums, k) { // 双端队列优化时间复杂度, 时间复杂度O(n) @@ -140,6 +152,11 @@ var maxSlidingWindow = function (nums, k) { }; ``` +**复杂度分析** + +- 时间复杂度:$$O(N * k)$$,如果使用双端队列优化的话,可以到 $$O(N)$$ +- 空间复杂度:$$O(k)$$ + Python3: ```python @@ -147,8 +164,10 @@ class Solution: def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: deque, res, n = collections.deque(), [], len(nums) for i in range(n): + # 移除前面实现的元素,整因为如此,才需要双端队列 while deque and deque[0] < i - k + 1: deque.popleft() + # 下面三行,类似单调递增栈 while deque and nums[i] > nums[deque[-1]]: deque.pop() deque.append(i) @@ -160,7 +179,7 @@ class Solution: **复杂度分析** - 时间复杂度:$$O(N)$$ -- 空间复杂度:$$O(N)$$ +- 空间复杂度:$$O(k)$$ ## 扩展