当前位置 博文首页 > Inmaturity_7的博客:算法练习帖--49--滑动窗口最大值(Java)

    Inmaturity_7的博客:算法练习帖--49--滑动窗口最大值(Java)

    作者:[db:作者] 时间:2021-08-01 08:42

    滑动窗口最大值

    一、题目简介

    给你一个整数数组 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]);
                }