【数据结构与算法】滑动窗口

滑动窗口

  1. 可以理解为一个可以容纳n个元素的窗口,通过每次记录窗口的状态,找到符合条件的窗口或者说在窗口中得到符合条件的元素。
  2. 通过滑动窗口可以减少时间复杂度

【题目】有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次 向右边滑一个位置。
例如, 数组为[4,3,5,4,3,3,6,7], 窗口大小为3时:

窗口滑动过程 窗口中的最大值
[ 4 3 5 ] 4 3 3 6 7 5
4 [3 5 4] 3 3 6 7 5
4 3 [ 5 4 3] 3 6 7 5
4 3 5 [ 4 3 3 ] 6 7 4
4 3 5 4 [3 3 6 ] 7 6
4 3 5 4 3 [ 3 6 7] 7

如果数组长度为n, 窗口大小为w, 则一共产生n-w+1个窗口的最大值。
请实现一个函数。 输入:整型数组arr, 窗口大小为w。
输出:一个长度为n-w+1的数组res, res[i]表示每一种窗口状态下的 以本题为例, 结果应该返回{5,5,5,4,6,7}。

【代码实现】

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

public class SildingWindow {
    public static void main(String[] args) {
        int[] arr={4,3,5,4,3,3,6,7};
        int[] res = slidingWindow(arr, 3);
        System.out.println(Arrays.toString(res));
    }

    /*如果数组长度为n, 窗口大小为w, 则一共产生n-w+1个窗口的最大值。
请实现一个函数。 输入:整型数组arr, 窗口大小为w。
输出:一个长度为n-w+1的数组res, res[i]表示每一种窗口状态下的 以本题为例, 结果应该
返回{5,5,5,4,6,7}。*/
    public static int[] slidingWindow(int[] arr, int w) {
        //1.定义一个双端队列,存放的是arr数组的下标
        LinkedList<Integer> deque = new LinkedList<>();
        //2.定义一个数组用来保存窗口最大值
        int[] res = new int[arr.length - w +1];
        int index=0;  //辅助变量给res使用
        for (int i = 0; i < arr.length; i++) {  //3.从左到右移动窗口

            while (!deque.isEmpty() && arr[deque.peekLast()] <= arr[i]) { // 4.判断添加的时候是否需要将deque中last元素弹出
                //当deque中最后一个值对应的arr的值小于或者等于ar[i]的时候,要将deque最后的值弹出直到arr[last]的值大于arr[i]或者deque为空
                deque.pollLast();
            }
            deque.addLast(i);  //将当前位置的索引加入到队列中
            if(deque.peekFirst()==i-w){
                deque.pollFirst();
            }
            if (i >=w - 1) {  //由于i要至少到大w-1位置这个时候窗口才是满的 刚开始窗口中的数的个数为1,2...w
                res[index++]=arr[deque.peekFirst()];    //5.将窗口最大值加入数组
            }
        }
        return res;
    }
}

【总结】

  • 每个位置的数最多进窗口一次出窗口一次,弹出过的数不会找回

  • 如果滑过的数字为n,双端队列更新的总代价时间复杂度O(N)

  • 双端队列滑过n次,双端队列更新的平均代价时间复杂度O(1)

上一篇:关于C++中二维和多维vector, deque, array的表示


下一篇:C++学习笔记 (五)标准模板库STL之容器