思路
暴力解法: 对每个窗口,都单独遍历窗口内的最大值。 时间复杂度为O(nk)
优化解法:因为每次窗口的变化,仅涉及到一个元素出,一个元素入。因此,可以维护一个堆,通过操作堆,我们可以通过O(1)的复杂度获取当前窗口的最大值。
再次优化:对于一个堆而言,每次出入元素都需要调整堆,但很多时候的调整是没必要的。
我们思考这样一种情况,如果当前窗口有两个下标i,j,且i<j,同时nums[i] <= nums[j]。那么堆中记录nums[i]是毫无意义的。因为滑动窗口向右移动,i在窗口时,j也一定在窗口,所以我们就可以将nums[i]移除。
因此我们可以使用一个队列存储所有还没有被移除的下标。在队列中,这些下标按照从小到大的顺序被存储,并且它们在数组 nums 中对应的值是严格单调递减的。
Python版本
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
res = []
# 双端队列
q = deque()
n = len(nums)
for i in range(n):
# 当前元素是否能加入到单调队列的末尾
while q and nums[q[-1]] < nums[i]:
q.pop()
q.append(i)
# 判断当前队首元素是否在窗口内
if i - q[0] >= k:
# 移除队首
q.popleft()
if i >= k - 1:
res.append(nums[q[0]])
return res
Java版本
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] ans = new int[n-k+1];
Deque<Integer> q = new ArrayDeque();
for (int i = 0;i<n;i++){
while (!q.isEmpty() && nums[q.getLast()] < nums[i]){
q.removeLast();
}
q.addLast(i);
if (i - q.getFirst() >= k){
q.removeFirst();
}
if (i >= k - 1){
ans[i-k+1] = nums[q.getFirst()];
}
}
return ans;
}
}