题目
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例:
输入: 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
使用双端队列解决
public static void main(String[] args) {
int[] origin = {1, 3, -1, -3, 5, 3, 6, 7};
int k = 3;
int[] result = maxSlidingWindow(origin, k);
for (int i : result) {
System.out.println(i);
}
}
/**
* 滑动窗口最大值
*
* @param nums 原始数组
* @param k 窗口长度
* @return
*/
private static int[] maxSlidingWindow(int[] nums, int k) {
// 双端队列,作为窗口滑动过程中获取最大值,存储数组下标
Deque<Integer> window = new ArrayDeque<>();
// 保存结果
List<Integer> resultTemp = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
// 开始滑动(0,1,2此时还不需要滑动,因为窗口大小是3,从下标3开始,才开始向右滑动),
// 同时如果窗口中的head元素则弹出最左侧的第一个元素,即head
if (i >= k && window.peekFirst() <= (i - k)) {
window.pollFirst();
}
// window中head只能是当前最大的数字下表,新进入滑动串口的值从后依次向前比,
// 比他小的都要移除,直到没有没有比他小的,则放入窗口的tail中
while (!window.isEmpty() && nums[window.peekLast()] <= nums[i]) {
window.pollLast();
}
window.add(i);
// 从下标2包括2开始,将每个窗口内的最大值记录结果集中
if (i >= k - 1) {
resultTemp.add(nums[window.getFirst()]);
}
}
int[] result = new int[resultTemp.size()];
for (int i = 0; i < resultTemp.size(); i++) {
result[i] = resultTemp.get(i);
}
return result;
}