算法练习(六):滑动窗口的最大值

题目:给定一个数组 nums 和滑动窗口的大小 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

  

提示:

你可以假设 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

解题思路:

设窗口区间为 [i, j] ,最大值为 xj 。当窗口向前移动一格,则区间变为[i + 1, j + 1],即添加了nums[j + 1], 删除了nums[i]。

若只向窗口[i, j] 右边添加数字nums[j + 1],则新窗口最大值可以通过一次对比 使用O(1)时间得到, 即:

  xj + 1 = max(xj,nums[j + 1]) 

而由于删除的nums[i]可能恰好是窗口内唯一的最大值xj,因此不能通过以上方法计算xj + 1,而必须使用O(j - i)时间,遍历整个窗口区间获取最大值,即:

  xj+1​=max(nums(i+1),⋯,num(j+1))

根据以上分析,可得 暴力法 的时间复杂度为 O(nk) 。

  • 设数组 nums 的长度为 n,则共有 (n-k+1) 个窗口;
  • 获取每个窗口最大值需线性遍历,时间复杂度为 O(k)。

算法练习(六):滑动窗口的最大值

 

 

 

算法流程:

  1. 初始化: 双端队列 deque ,结果列表 res ,数组长度 n ;
  2. 滑动窗口: 左边界范围 i∈[1−k,n−k] ,右边界范围 j ∈[0,n−1] ;

     1、若 i > 0 且 队首元素 deque[0] == 被删除元素 nums[i - 1] :则队首元素出队;

     2、删除 deque 内所有 < nums[j] 的元素,以保持 deque 递减;
     3、将 nums[j]添加至 deque 尾部;
     4、若已形成窗口(即 i ≥ 0 ):将窗口最大值(即队首元素 deque[0] )添加至列表 res;

 

   3. 返回值: 返回结果列表 res;

package Algriothm;

import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;

public class SlidingWindow {


    public static void main(String[] args) {
        System.out.println(Arrays.toString(maxSlidingWindow(new int[]{1, 3, -1, -3, 5, 3, 6, 7}, 3)));;
    }

    public static int[] maxSlidingWindow(int[] nums, int k) {

        if (nums.length == 0 || k == 0) return new int[0];
        Deque<Integer> deque = new LinkedList();
        int[] res = new int[nums.length - k + 1];
        for (int i = 0; i < k; i++) {
            while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
                deque.removeLast();
            }
            deque.addLast(nums[i]);
        }
        res[0] = deque.peekFirst();
        for (int i = k; i < nums.length; i++) {
            if (deque.peekFirst() == nums[i - k]) {
                deque.removeFirst();
            }
            while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
                deque.removeLast();
            }
            deque.addLast(nums[i]);
            res[i - k + 1] = deque.peekFirst();
        }
        return res;
    }
    
}

  

上一篇:C++空类以及没有成员变量的类的大小


下一篇:必会算法总结3—拓扑排序