滑动窗口最大值
一、题目简介
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
(题目来源:力扣(LeetCode))
示例 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]
示例 3:
输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:
输入:nums = [9,11], k = 2
输出:[11]
示例 5:
输入:nums = [4,-2], k = 2
输出:[4]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
这道题和leecode简单题59一样
二、解决方法
1. 单调队列
package com.lxf.test;
import java.util.LinkedList;
public class MaxSlidingWindow {
public static void main(String[] args) {
//[1,3,-1,-3,5,3,6,7]
// 3
maxSlidingWindow(new int[]{
1,3,-1,-3,5,3,6,7},3);
}
public static int[] maxSlidingWindow(int[] nums, int k) {
if(k==1||nums.length==0) return nums;
int[] results=new int[nums.length-k+1];
//单调队列
LinkedList<Integer> linkedList = new LinkedList<>();
for (int i = 0; i < nums.length; i++) {
//保证队列头是当前窗口的最大值
while(!linkedList.isEmpty()&&nums[linkedList.peekLast()]<nums[i]){
linkedList.pollLast();
}
//将当前数组值对应下标加入队列中
linkedList.offer(i);
//从第一个窗口开始取数
if(i>=k-1){
//将当前队列头也就是当前窗口的最大值赋值到结果数组中
results[i-k+1]=nums[linkedList.peek()];
//预测队列头是否在下一个窗口中,不在就要移除它
//例如:nums=[1,5,2,4,9] k=3
//其中5在第一个窗口和第二个窗口中,在第三个窗口前就要移除
if(linkedList.peek()<=i-k+1){
linkedList.pollFirst();
}
}
}
return results;
}
}
2. 双端队列(官方题解)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
Deque<Integer> deque = new LinkedList<Integer>();
//获取第一个窗口的最大值,
for (int i = 0; i < k; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
}
int[] ans = new int[n - k + 1];
ans[0] = nums[deque.peekFirst()];
//从第二个窗口开始遍历(比方法1少了一层比较)
for (int i = k; i < n; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
while (deque.peekFirst() <= i - k) {
deque.pollFirst();
}
ans[i - k + 1] = nums[deque.peekFirst()];
}
return ans;
}
}
3. 分块 (超时)
package com.lxf.test;
import java.util.Arrays;
public class MaxSlidingWindow {
public static void main(String[] args) {
//[1,3,-1,-3,5,3,6,7]
// 3
System.out.println(maxSlidingWindow(new int[]{
1, 3, -1, -3, 5, 3, 6, 7}, 3));
}
public static int[] maxSlidingWindow(int[] nums, int k) {
if(k==1||nums.length==0) return nums;
int[] results=new int[nums.length-k+1];
Arrays.fill(results, Integer.MIN_VALUE);
for (int i = 0; i < nums.length; i++) {
if(i==nums.length-k){
break;
}
int j=i;
while(j<i+k){
results[i]=Math.max(results[i],nums[j]);
j++;
}
}
return results;
}
}
4. 分块 + 预处理(官方题解)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] prefixMax = new int[n];
int[] suffixMax = new int[n];
for (int i = 0; i < n; ++i) {
if (i % k == 0) {
prefixMax[i] = nums[i];
}
else {
prefixMax[i] = Math.max(prefixMax[i - 1], nums[i]);
}
}
for (int i = n - 1; i >= 0; --i) {
if (i == n - 1 || (i + 1) % k == 0) {
suffixMax[i] = nums[i];
} else {
suffixMax[i] = Math.max(suffixMax[i + 1], nums[i]);
}
}
int[] ans = new int[n - k + 1];
for (int i = 0; i <= n - k; ++i) {
ans[i] = Math.max(suffixMax[i], prefixMax[i + k - 1]);
}
return ans;
}
}