滑动窗口最大值问题
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
问题分析
可使用单调队列解决问题(java中使用LinkedList来实现单调队列),队列从头到尾是从大到小的,那么队头元素就是需要返回的最大值,只需每次让队头弹出就行。当滑动窗口移动时,我们需要弹出在窗口外的元素,因为是按大小顺序入的队,所以队首元素不一定是需要弹出的元素,如何解决呢?
其实没有必要将所有元素都入队,只需要保证队列元素是从大到小的,并且保证可能成为最大值的元素都入队。
具体操作
- 入队时,判断队尾元素是否小于该元素,是则弹出队尾元素,直到否时将该元素入队。
- 滑动窗口滑动时移除元素的操作,因为滑动窗口的范围为[i-k+1,i],所以当队首元素小于等于nums[i-k]时,表示当前队首元素在滑动窗口外,需要移除。
代码
public int[] maxSlidingWindow(int[] nums, int k) {
//如果数组为空,或者小于2直接返回
if(nums == null || nums.length < 2) {
return nums;
}
// 单调队列,从大到小保存当前窗口中的值,不一定是全部值,是可能成为滑动窗口最大值的元素
LinkedList<Integer> queue = new LinkedList();
// 保存结果数组
int[] result = new int[nums.length-k+1];
// 遍历nums数组,实现滑动窗口的操作
for(int i = 0;i < nums.length;i++){
// 保证队列里的元素从大到小 如果队尾元素小于当前待入队元素,则需要依次弹出,直至满足要求
while(!queue.isEmpty() && queue.peekLast() < nums[i]){
queue.pollLast();
}
//将元素加入队列
queue.addLast(nums[i]);
// 判断当前队列中队首元素是否为滑动后需要移除的元素,滑动窗口的范围为[i-k+1,i]
if(i+1 > k && queue.peek() <= nums[i-k]){
queue.poll();
}
//保存窗口中最大值
if(i+1 >= k){
result[i+1-k] = queue.peek();
}
}
return result;
}