1. 题目描述
题目来源:力扣
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例1. 输入: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. 输入:nums = [1], k = 1 输出:[1]
2. 题解
2.1 题解思路
方法1,暴力解法
每一次滑动窗存储k个元素,每次调用max对k个值求最大值,因此算法的复杂度为O(n*k),代码如下,
class Solution(object):
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
stack = []
r = []
if len(nums) <= k:
r.append(max(nums))
return r
for i in range(k):
stack.append(nums[i])
r.append(max(stack))
for i in range(k, len(nums)):
stack.pop(0)
stack.append(nums[i])
r.append(max(stack))
return r
方法2,单调队列
栈的特点:后入先出,先入后出;和队列正好相反,队列先入先出。栈和对列的示意图如下,
图1. 栈和队列
单调队列是指,队列内的元素按照从小到大或者从大到小的顺序排列。对于一个单调递减的单调队列,出口元素(第一个元素)为最大的元素,那么在遍历n个元素的过程中,首先将第一个元素压入队列内,下面:
pop(出口元素):若此时的移动窗口已滑过当前的值,那么pop出口元素;
insert(入口元素):若是当前val大于入口元素,那么,pop入口元素,直到val<=入口元素为止。当前val入队列。(保证了队列是单调的,且在窗口内可能会成为最大值)
因此,在改题目中,单调栈内维护的元素为在窗口大小k内可能成为最大值的元素,且包含重复值(防止当前元素为最大,但是由于上一个元素相等且已移出队列。)
代码如下,
class Solution(object):
def pop(self, queue, ele):
if queue != [] and queue[0] == ele:
queue.pop(0)
return queue
def push(self, queue, ele):
while queue != [] and ele > queue[-1]:
queue.pop(-1)
queue.append(ele)
return queue
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
r = []
queue = []
for i in range(k):
queue = self.push(queue, nums[i])
r.append(queue[0])
for i in range(k, len(nums)):
queue = self.pop(queue, nums[i-k])
queue = self.push(queue, nums[i])
r.append(queue[0])
return r
在上面的解法中,运行测试时间为9320ms,换用动态的from array import array使用动态的数组,将
r = []
queue = []
换为
r = array('h', [])
queue = array('h', [])
其中h代表signed short int,代码如下,
from array import array
class Solution(object):
def pop(self, queue, ele):
if len(queue) != 0 and queue[0] == ele:
queue.pop(0)
return queue
def push(self, queue, ele):
while len(queue) != 0 and ele > queue[-1]:
queue.pop(-1)
queue.append(ele)
return queue
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
# r = array('l', [])
# queue = array('l', [])
r = array('h', [])
queue = array('h', [])
for i in range(k):
queue = self.push(queue, nums[i])
r.append(queue[0])
for i in range(k, len(nums)):
queue = self.pop(queue, nums[i-k])
queue = self.push(queue, nums[i])
r.append(queue[0])
return list(r)
运行时间缩短为2852ms。因此可见,动态数组在pop元素时效率比静态数组高。
关于from array import array,用法见python中 array模块学习笔记_阿常呓语的博客-CSDN博客。