239. 滑动窗口最大值
给你一个整数数组 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
思路和算法
对于最大值问题,可以使用基于大顶堆的优先队列,优先队列的队首元素为优先队列中的最大元素。从左到右遍历数组 nums 并依次将每个元素加入优先队列,则当遍历到下标 i 时,优先队列的队首元素为数组 nums 从下标 0 到下标 i 的全部元素中的最大元素。
由于题目要求计算每个滑动窗口的最大值,因此对于每个滑动窗口,优先队列中的最大元素必须位于该滑动窗口的下标范围内,即当遍历到下标 i 时,如果 i≥k−1,则优先队列中的最大元素对应的下标必须在范围 [i−k+1,i] 内。为了确保优先队列中的最大元素对应的下标在滑动窗口的下标范围内,优先队列需要同时存储元素和对应下标,优先队列仍满足队首元素为优先队列中的最大元素。
创建长度为 n−k+1 的数组 maxArray 作为结果数组,则 maxArray[i] 表示数组 nums 从下标 i 到下标 i+k−1 的滑动窗口中的最大值。
首先遍历 nums[0] 到 nums[k−1],将每个元素和对应下标加入优先队列,令 maxArray[0] 等于这 k 个元素中的最大值。然后遍历 nums[k] 到 nums[n−1],对于每个下标 i,其对应的滑动窗口的下标范围是 [i−k+1,i],进行如下操作:
将 nums[i] 和下标 i 加入优先队列;
如果优先队列的队首元素对应下标小于等于 i−k,则将优先队列的队首元素取出,重复该过程直到优先队列的队首元素对应下标大于 i−k;
将优先队列的队首元素赋给 maxArray[i−k+1]。
遍历结束之后,maxArray 的每个下标处的元素即为以该下标作为开始下标的滑动窗口中的最大值。
参考storm大神做法
`
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int length = nums.length;
int[] maxArray = new int[length - k + 1];
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] arr1, int[] arr2) {
return arr2[0] - arr1[0];
}
});
for (int i = 0; i < k; i++) {
pq.offer(new int[]{nums[i], i});
}
maxArray[0] = pq.peek()[0];
for (int i = k; i < length; i++) {
pq.offer(new int[]{nums[i], i});
while (pq.peek()[1] <= i - k) {
pq.poll();
}
maxArray[i - k + 1] = pq.peek()[0];
}
return maxArray;
}
}
`
浙公网安备 33010602011771号