📅  最后修改于: 2023-12-03 15:40:00.670000             🧑  作者: Mango
给定一个数组,和一个滑动窗口的大小,请找出所有滑动窗口里数值的最大值。
例如,输入数组{2, 3, 4, 2, 6, 2, 5, 1}
,以及滑动窗口的大小为3,则一共有6个滑动窗口,它们的最大值分别为4, 4, 6, 6, 6, 5
。
我们可以使用一个双端队列来实现这个算法。队列中存储的是数组中的下标,队列的头部元素为当前滑动窗口的最大值所在的下标。
我们对数组进行遍历,对于每一个元素,如果队列不为空并且队列的队尾下标对应的元素小于等于当前元素,则将队列的队尾元素出队,直到队列为空或队尾元素大于当前元素。然后将当前元素下标入队。
如果队列的头部元素所对应的下标小于当前滑动窗口的左边界,则将头部元素出队。此时队列头部元素所对应的元素为当前滑动窗口的最大值。
public List<Integer> maxInWindows(int[] nums, int k) {
List<Integer> res = new ArrayList<>();
if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) {
return res;
}
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < nums.length; i++) {
// 如果队列不为空并且队尾元素小于当前元素,则出队
while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
deque.pollLast();
}
// 把当前元素添加到队尾
deque.offerLast(i);
// 如果队列头部元素所对应的下标小于当前滑动窗口的左边界,则将头部元素出队
while (deque.peekFirst() < i + 1 - k) {
deque.pollFirst();
}
// 如果窗口的长度达到了 k,则队列头部元素所对应的元素为当前窗口的最大值
if (i >= k - 1) {
res.add(nums[deque.peekFirst()]);
}
}
return res;
}
由于每个元素最多入队一次,出队一次,因此时间复杂度为O(n)。
队列中最多存储k个元素,因此空间复杂度为O(k)。