239. 滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]解释:
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
2.暴力
遍历数组
时间复杂度和空间复杂度都比较高
class Solution:
def maxSlidingWindow(self, nums: 'List[int]', k: 'int') -> 'List[int]':
n = len(nums)
if n == 0 or k == 0:
return []
if k == 1: return nums
return [max(nums[i:i + k]) for i in range(n - k + 1)]
3.动态规划
把数组分成长度为k(滑动窗口的长度)的块
用left记录从左到右遍历每个块的当前最大值
用right记录从右到左遍历每个块的当前最大值
则滑动窗口[i:j]的最大值在对应位置的left[j] 或者right[i]
class Solution:
def maxSlidingWindow(self, nums: 'List[int]', k: 'int') -> 'List[int]':
n = len(nums)
if n == 0 or k == 0:
return []
if k == 1: return nums
left = [0] * n
left[0] = nums[0]
right = [0] * n
right[n - 1] = nums[n - 1]
for i in range(1, n):
if i % k == 0:
left[i] = nums[i]
else:
left[i] = max(left[i - 1], nums[i])
j = n - i - 1
if (j + 1) % k == 0:
right[j] = nums[j]
else:
right[j] = max(right[j + 1], nums[j])
result = []
for i in range(n - k + 1):
result.append(max(left[i + k - 1], right[i]))
return result
4.双端队列
collections 是 python 内建的一个集合模块,里面封装了许多集合类,其中队列相关的集合只有一个:deque。
deque 是双边队列(double-ended queue),具有队列和栈的性质,在 list 的基础上增加了移动、旋转和增删等。
https://blog.csdn.net/happyrocking/article/details/80058623
1.用队列记录最大值的位置(有点抽象不好理解,特别是if和while的判断语句,知其然不知其所以然)
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
if n == 0 or k == 0:
return []
if k == 1: return nums
deque = collections.deque()
result = []
for i in range(len(nums)):
#i表示滑动窗口的最后一位,判断队列是否超出窗口
if deque and deque[0] <= i - k:
a=deque.popleft()
#print("a=",a)
#新进来的元素需要与窗口中元素比较,弹出小于新元素的所有元素
while deque and nums[i] > nums[deque[-1]]:
b=deque.pop()
#print("b=",b)
deque.append(i)
#print("d=",deque)
if i >= k - 1:
result.append(nums[deque[0]])
#print(result)
return result
2.用队列直接记录元素
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums or k == 0:
return []
cur_max = max(nums[ : k])
res = [cur_max]
size = len(nums)
for i in range(1, size - k + 1):
# 如果最大值是移走的元素,那就重新计算最大值。
if nums[i - 1] == cur_max:
cur_max = max(nums[i : i + k])
# 表明最大值就在当前的区域中,需和新加入的元素相比较。
else:
cur_max = max(cur_max, nums[i + k -1])
res.append(cur_max)
return res