@@ -56,7 +56,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/
5656## 思路
5757
5858符合直觉的想法是直接遍历 nums, 然后然后用一个变量 slideWindow 去承载 k 个元素,
59- 然后对 slideWindow 求最大值,这是可以的,时间复杂度是 O(n \* k).代码如下:
59+ 然后对 slideWindow 求最大值,这是可以的,遍历一次的时间复杂度是 $N$,k 个元素求最大值时间复杂度是 $k$, 因此总的时间复杂度是 O(n \* k).代码如下:
6060
6161JavaScript:
6262
@@ -90,18 +90,28 @@ class Solution:
9090```
9191
9292但是如果真的是这样,这道题也不会是 hard 吧?这道题有一个 follow up,要求你用线性的时间去完成。
93- 我们可以用双端队列来完成,思路是用一个双端队列来保存` 接下来的滑动窗口可能成为最大值的数 ` 。具体做法:
9493
95- - 入队列
94+ 其实,我们没必须存储窗口内的所有元素。 如果新进入的元素比前面的大,那么前面的元素就不再有利用价值,可以直接移除。这提示我们使用一个[ 单调递增栈] ( ../thinkings/monotone-stack.md " 单调栈专题 ") 来完成。
95+
96+ 但由于窗口每次向右移动的时候,位于窗口最左侧的元素是需要被擦除的,而栈只能在一端进行操作。
97+
98+ 而如果你使用数组实现,就是可以在另一端操作了,但是时间复杂度仍然是 $O(k)$,和上面的暴力算法时间复杂度一样。
99+
100+ 因此,我们考虑使用链表来实现,维护两个指针分别指向头部和尾部即可,这样做的时间复杂度是 $O(1)$,这就是双端队列。
101+
102+ 因此思路就是用一个双端队列来保存` 接下来的滑动窗口可能成为最大值的数 ` 。
103+
104+ 具体做法:
96105
106+ - 入队列
97107- 移除失效元素,失效元素有两种
98108
991091 . 一种是已经超出窗口范围了,比如我遍历到第 4 个元素,k = 3,那么 i = 0 的元素就不应该出现在双端队列中了
100110 具体就是` 索引大于 i - k + 1的元素都应该被清除 `
101111
1021122 . 小于当前元素都没有利用价值了,具体就是` 从后往前遍历(双端队列是一个递减队列)双端队列,如果小于当前元素就出队列 `
103113
104- 如果你仔细观察的话,发现双端队列其实是一个递减的一个队列。 因此队首的元素一定是最大的。用图来表示就是:
114+ 经过上面的分析,不难知道双端队列其实是一个递减的一个队列, 因此队首的元素一定是最大的。用图来表示就是:
105115
106116![ ] ( https://tva1.sinaimg.cn/large/007S8ZIlly1ghltxg29buj30hb0di757.jpg )
107117
@@ -115,6 +125,8 @@ class Solution:
115125
116126JavaScript:
117127
128+ JS 的 deque 实现我这里没有写, 大家可以参考 [ collections/deque] ( https://github.com/montagejs/collections/blob/master/deque.js )
129+
118130``` js
119131var maxSlidingWindow = function (nums , k ) {
120132 // 双端队列优化时间复杂度, 时间复杂度O(n)
@@ -140,15 +152,22 @@ var maxSlidingWindow = function (nums, k) {
140152};
141153```
142154
155+ ** 复杂度分析**
156+
157+ - 时间复杂度:$$ O(N * k) $$ ,如果使用双端队列优化的话,可以到 $$ O(N) $$
158+ - 空间复杂度:$$ O(k) $$
159+
143160Python3:
144161
145162``` python
146163class Solution :
147164 def maxSlidingWindow (self , nums : List[int ], k : int ) -> List[int ]:
148165 deque, res, n = collections.deque(), [], len (nums)
149166 for i in range (n):
167+ # 移除前面实现的元素,整因为如此,才需要双端队列
150168 while deque and deque[0 ] < i - k + 1 :
151169 deque.popleft()
170+ # 下面三行,类似单调递增栈
152171 while deque and nums[i] > nums[deque[- 1 ]]:
153172 deque.pop()
154173 deque.append(i)
@@ -160,7 +179,7 @@ class Solution:
160179** 复杂度分析**
161180
162181- 时间复杂度:$$ O(N) $$
163- - 空间复杂度:$$ O(N ) $$
182+ - 空间复杂度:$$ O(k ) $$
164183
165184## 扩展
166185
0 commit comments