problem
Given an array nums, there is a sliding window of size k which is
moving from the very left of the array to the very right. You can only
see the k numbers in the window. Each time the sliding window moves
right by one position.
solution
可以维持长度为k的子数组有序,这样在滑动窗口时可以直接插入和删除元素,时间复杂度为 O(n∗k) .
上面的算法可以改变存储的数据结构,使用堆来存储子数组中的元素,这样调整时复杂度为logk,所以整体的时间复杂度就是 O(n∗logk)
这个问题其实关键就在于找到合适的数据结构,使得可以快速找到最大值,并且可以排除已经不再窗口中的值。
我们可以使用双端队列来实现这个功能
1. 每次入队如果新元素比队尾元素小,则将其删除,直至队尾元素大于新元素或队空。(因为被删除元素既没有当前元素大,也没有当前元素新,所以肯定不会替代当前元素成为最大值的)
2. 找最大值时从队头开始,如果队头元素对应的index不在当前窗口则将其删除,直到找到在窗口中的元素,即为最大值。
class Solution(object):
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
if not nums:
return []
from collections import deque
dq = deque()
n = len(nums)
ans = []
for i in range(k-1):
#把前k-1个元素入队
while len(dq) > 0:
if nums[dq[-1]] <= nums[i]:
dq.pop()
else:
break
dq.append(i)
for i in range(k-1, n):
while len(dq) > 0:
if nums[dq[-1]] <= nums[i]:
dq.pop()
else:
break
dq.append(i)
while dq[0] < i-k+1:
dq.popleft()
ans.append(nums[dq[0]])
return ans
改进:
可以使用一个list和指针模拟deque,思路相同,只是在实现细节上有些差别。
总结
关键在于如何找到最大值,最简单的想法就是保持数组有序,那么第一个就是最大的,关键在于如何维持这个数组的属性:有序,我们根据问题的属性可以发现对于小于当前值得元素可以直接删除,那么就可以在 O(n) 的时间实现。