原題
給出一個可能包含重復的整數數組,和一個大小為 k 的滑動窗口, 從左到右在數組中滑動這個窗口,找到數組中每個窗口內的最大值。
給出數組 [1,2,7,7,8], 滑動窗口大小為 k = 3. 返回 [7,7,8].
最開始,窗口的狀態如下:
[1, 2 ,7
,7 , 8], 最大值為 7;
然后窗口向右移動一位:
[1, 2, 7, 7
, 8], 最大值為 7;
最后窗口再向右移動一位:
[1, 2, 7, 7, 8
], 最大值為 8.
解題思路
- 方法一:最直觀的,每次從起點
i
遍歷一遍窗口長度j = i, i + k
,找最大值,兩層for循環,時間復雜度O(n * k) - 方法二:維護一個hash heap,每次移動,加入右邊元素O(logk),減去左邊元素O(logk),返回maxheap中的最大值O(1),時間復雜度為O(n * logk)
- 使用Deque,維護一個遞減的deque,時間復雜度為O(n)
已知 [1, 2, 7, 3, 8, 5, 3, 2]
[1], 2進入, 2 > 1 彈出1
[2], 7進入, 7 > 2 彈出2
[7], 第一個窗口最大值為7,3進入,3 < 7
[7, 3], 第二個窗口最大值為7,8進入, 8 > 3 彈出3
[7], 8 > 7, 彈出7
[8], 第三個窗口最大值為8
為什么要用deque呢?注意這種情況
當前為[9, 8, 7], 6進入,6 < 7, 6進入
[9, 8, 7, 6] 但是對K=3的窗口,必須要彈出9,這步就要用到deque
- Python中使用deque, 和list的API類似,多了
popleft
,appendleft
,extendleft
import collections
d = collections.deque()
d.extend([1, 2, 3])
d.pop() # 3
d.popleft() # 1
d.append() # [2, 10]
d.appendleft() # [20, 2, 10]
d[0] # peek at leftmost item
d[-1] # peek at rightmost item
if d:
# d is not empty
else:
# d is empty
完整代碼
import collections
class Solution(object):
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
res = []
d = collections.deque()
for i in range(len(nums)):
while d and d[-1] < nums[i]:
d.pop()
d.append(nums[i])
if i > k - 1 and d[0] == nums[i - k]:
d.popleft()
if i >= k - 1:
res.append(d[0])
return res