解题随记
题目
给你一个整数数组 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]
提示:
1 <= nums.length <= 105-104 <= nums[i] <= 1041 <= k <= nums.length
解题思路
划重点
- 窗口内数组中最大值(窗口内无序)
- 每次窗口右移1位(左边丢弃一位),所以窗口的位置
[i - k + 1,i]
思路
- 用
PriorityQueue解决最大值问题,设置最大值始终保留在队首。
Tips:PriorityQueue为线程不安全的优先级队列,内部实现为大小堆(树),保障队列中数据始终按照某一优先级排列,最常使用的为单调递增或单调递减
- 由于我们还需要判断窗口位置,所以还需要记录数据的索引下标,故可以使用int[2]、pair等数据结构来存储数据值和下标
解法示例
参照leetcode官方题解
// 设置优先级规则,当数据值不一样的时候,数据值大的在前;当数据值一样的时候,下标值大的在前面
PriorityQueue<int[]> queue = new PriorityQueue<>((ints1, ints2) -> ints1[0] != ints2[0] ? ints2[0] - ints1[0] : ints2[1] - ints1[1]);
// 前k-1个数提前入队
for (int i = 0; i < k - 1; i++) {
queue.add(new int[]{nums[i], i});
}
// 结果集
int[] result = new int[nums.length - k + 1];
// 从k -1 开始,每次循环都会产生一个结果
for (int i = k - 1; i < nums.length; i++) {
// 先入队,此时满足窗口大小,可以计算最大值到结果集当中
queue.add(new int[]{nums[i], i});
// 判断如果队首的下标大于窗口的最左侧下标,代表不应该存在于窗口中被计算,所以对应要出队
while (!queue.isEmpty() && queue.peek()[1] < i - k + 1) {
queue.poll();
}
// 记录最大值即可
result[i - k + 1] = queue.peek()[0];
}
return result;