给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
示例 2:
输入:nums = [1], k = 1
输出:[1]
示例 3:
输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:
输入:nums = [9,11], k = 2
输出:[11]
示例 5:
输入:nums = [4,-2], k = 2
输出:[4]
双端队列存储最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> queue = new LinkedList<>();
int len = nums.length;
int[] result = new int[len - k + 1];
for (int i = 0; i < len; i++) {
while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i])
queue.pollLast();
queue.addLast(i);
if (queue.peek() <= i - k)
queue.poll();
if (i >= k - 1) {
result[i - k + 1] = nums[queue.peek()];
}
}
return result;
}
}
优先队列存储
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
PriorityQueue<int[]> queue = new PriorityQueue<>((p1, p2) ->
p1[0] != p2[0] ? p2[0] - p1[0] : p2[1] - p1[1]);
int len = nums.length;
for (int i = 0; i < k; ++i)
queue.offer(new int[]{nums[i], i});
int[] result = new int[len - k + 1];
for (int i = 0; i < len; i++) {
queue.offer(new int[]{nums[i], i});
if (i >= k - 1) {
while (queue.peek()[1] <= i - k)
queue.poll();
result[i - k + 1] = queue.peek()[0];
}
}
return result;
}
}
分块 + 预处理
将数组 nums \textit{nums} nums 从左到右按照 k 个一组进行分组:
- 如果 i 是 k 的倍数,那么 nums [ i ] \textit{nums}[i] nums[i] 到 nums [ i + k − 1 ] \textit{nums}[i+k-1] nums[i+k−1] 恰好是一个分组。我们只要预处理出每个分组中的最大值,即可得到答案;
- 如果 i 不是 k 的倍数,那么
nums
[
i
]
\textit{nums}[i]
nums[i] 到
nums
[
i
+
k
−
1
]
\textit{nums}[i+k-1]
nums[i+k−1] 会跨越两个分组,占有第一个分组的后缀以及第二个分组的前缀。假设 j 是 k 的倍数,并且满足
i
<
j
≤
i
+
k
−
1
i < j \leq i+k-1
i<j≤i+k−1,那么
nums
[
i
]
\textit{nums}[i]
nums[i] 到
nums
[
j
−
1
]
\textit{nums}[j-1]
nums[j−1] 就是第一个分组的后缀,
nums
[
j
]
\textit{nums}[j]
nums[j]到
nums
[
i
+
k
−
1
]
\textit{nums}[i+k-1]
nums[i+k−1]就是第二个分组的前缀。如果我们能够预处理出每个分组中的前缀最大值以及后缀最大值,同样可以在 O(1)的时间得到答案。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
int[] prefixMax = new int[len];
int[] suffixMax = new int[len];
for (int i = 0; i < len; ++i)
prefixMax[i] = i % k == 0? nums[i] : Math.max(prefixMax[i - 1], nums[i]);
suffixMax[len - 1] = nums[len - 1];
for (int i = len - 2; i >= 0; --i)
suffixMax[i] = (i + 1) % k == 0 ? nums[i] : Math.max(suffixMax[i + 1], nums[i]);
int[] result = new int[len - k + 1];
for (int i = 0; i <= len - k; ++i)
result[i] = Math.max(suffixMax[i], prefixMax[i + k - 1]);
return result;
}
}