求滑动窗口括起来的数组中的最大值。
最简单的方法就是暴力法,但时间复杂度为O(nk),这种hard题暴力法不用想都知道是不能过的。
思路1:
使用双端队列。用双端队列作为存储空间,存储方法如下
- 从左往右依次遍历数组,如果队列为空,那么将当前元素的添加到队列的左边(index和元素是一一对应的,入栈index相当于入栈了元素)
- 如果当前队列不为空,且当前元素小于等于队列最右端元素,那么将当前元素加入对垒最右边
- 否则,对队列进行pop操作,直到队列最右元素大于等于当前元素或队列为空
- 将当前元素处理过后,判断队列最左边的元素是否在滑动窗口的范围内,如果不在则删除(这就是为什么要存储下标而不存储值的原因)
AC代码
class Solution:
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
res = []
if k==0:
return res
from collections import deque
queue = deque()
for i in range(len(nums)):
while(len(queue)!=0 and nums[queue[-1]]<nums[i]):
queue.pop()
while(len(queue)!=0 and queue[0]<=i-k):
queue.popleft()
queue.append(i)
if i+1 >= k:
res.append(nums[queue[0]])
return res
思路2:
一般这种子区域的最大值或最小值都会想到用堆来做,但是堆一般只能pop最大或最小值,滑动窗口每次都要删除最左边的一个元素,所以要对堆进行小小的改进,加一个remove元素的方法,这里就不自己写方法了,使用python标准库的heapq,他可以将数组变成堆数组,每次删除元素后重新建立堆即可,时间复杂度为O(nk)(查找要删除的元素得顺序遍历)
class Solution:
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
res = []
import heapq
pq = []
for i in range(len(nums)):
if i>=k-1:
index = -1
for j in range(len(pq)):
if pq[j] == -nums[i-k]:
index = j
break
# print(pq.queue,index)
if index!=-1:
del pq[index]
heapq.heappush(pq, -nums[i])
heapq.heapify(pq)
res.append(-pq[0])
else:
heapq.heappush(pq,-nums[i])
return res
思路3
disscuss中某大神的思路
拿题目中nums = [1,3,-1,-3,5,3,6,7], and k = 3
为例
先根据k将数组分成一个个k
的子数组
1 3 -1 | -3 5 3 | 6 7]
假设在第i
个元素的时候,用max_left
和max_right
分别表示,i
左边元素的最大值和i右边元素的最大值(包括自己),注意这里的最大值是到边界为止的最大值(上面的|为边界)
,这样我们就能得到两个数组maxleft和maxright,这样,当前窗口的最大值为max(maxright(array_start),maxleft(arrat_end))
1 3 (-1 | -3 5 ) 3 | 6 7]
非常巧妙
class Solution:
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
if k ==0:
return []
maxleft = nums[:]
maxright = nums[:]
flag_left = nums[0]
flag_right = nums[-1]
for i in range(len(nums)):
left_index = i
right_index = len(nums)-i-1
if (left_index) % k==0:
flag_left =nums[left_index]
else:
flag_left =max(nums[left_index],flag_left)
maxleft[left_index] = flag_left
if (right_index+1) % k ==0:
flag_right = nums[right_index]
else:
flag_right = max(nums[right_index],flag_right)
maxright[right_index] =flag_right
res = []
for i in range(k-1,len(nums)):
res.append(max((maxleft[i]),maxright[i-k+1]))
return res