• 【deque】滑动窗口、双端队列解决数组问题


    C++手册之deque

    所属头文件 <deque>

    常用操作: 

    back()返回尾部元素;

    front()返回头部元素;

    push_back()尾部插入元素;

    pop_bakc()尾部删除元素;

    push_front()头部插入元素;

    pop_front()头部删除元素;


    问题1:求滑动窗口的最大值(《剑指offer面试题65》)

    描述:给定一个数组和滑动窗口的大小,找出所有滑动窗口里的最大值。

    示例:数组{2, 3, 4, 2, 6, 2, 5} 窗口大小为 3,一共有7-3+1=5个滑动窗口,返回这些窗口最大值的数组{4, 4, 6, 6, 6}

    方法:生成一个双端队列deque,里面存储可能成为滑动窗口最大值在数组中的下标

    vector<int> getMax(const vector<int> &arr, int size){
        vector<int> res;
        if (arr.size() == 0 || size <= 0){
            return res;
        }
        deque<int> index;
        int i = 0;
        while (i < arr.size()){
            while (!index.empty() && arr[index.back()] <= arr[i]){
                index.pop_back();
            }
            index.push_back(i);
            if (!index.empty() && index.front() == (i - size)){
                index.pop_front();//不属于当前窗口
            }
            if (i >= size - 1){
                res.push_back(arr[index.front()]);
            }
            i++;
        }
        return res;
    }

    问题2:给定一个数组,找出最大值与最小值之差小于等于给定数num的子数组的个数。(牛客左程云《程序员面试代码指南》)

    示例:给定数组{5, 2, 6, 3, 4, 1},num = 3,符合条件的子数组分别为{5} {5, 2} {2} {6} {6, 3} {6, 3, 4} {3} {3, 4} {3, 4, 1} {4} {4, 1} {1}返回数值12

    方法:生成两个双端队列qmax, qmin,第一层while循环i,满足条件的将i作为起始元素的子数组;第二层while循环,满足条件的将j作为尾元素的子数组。每次内while循环结束,结果res += j - i;

    qmax维护窗口子数组最大值在原数组中的下标;

    qmin维护窗口子数组最小值在原数组中的下标。

    窗口在动态发生变化,qmax和qmin的元素也在发生变化。

     1 int getNum(int arr[], int len, int num){
     2     if (arr == NULL || len < 1 ||num < 0)
     3         return 0;
     4     int res = 0;
     5     deque<int> qmax;
     6     deque<int> qmin;
     7     int i = 0;
     8     int j = 0;
     9     while (i < len){
    10         while (j < len){
    11             while (!qmax.empty() && arr[qmax.back()] <= arr[j]){
    12                 qmax.pop_back();
    13             }
    14             qmax.push_back(j);
    15             while (!qmin.empty() && arr[qmin.back()] >= arr[j]){
    16                 qmin.pop_back();
    17             }
    18             qmin.push_back(j);
    19             if (arr[qmax.front()] - arr[qmin.front()] > num){
    20                 break;
    21             }
    22             j++; //j一直在变大,不回退
    23         }
    24         if (qmax.front() == i){
    25             qmax.pop_front(); //不属于以i+1开头的窗口,弹出
    26         }
    27         if (qmin.front() == i){
    28             qmin.pop_front(); //不属于以i+1开头的窗口,弹出
    29         }
    30         res += j - i;
    31         i++; //i一直在变大,不回退
    32     }
    33     return res;
    34 }
  • 相关阅读:
    BZOJ2956: 模积和——整除分块
    BZOJ1257: [CQOI2007]余数之和——整除分块
    数位DP【模板】
    2019HDU多校第7场——构造
    AtCoder Grand Contest 032 B
    P3599 Koishi Loves Construction——构造题
    CF C. Vladik and fractions——构造题
    RMQ问题【模板】
    libevent多线程使用事项
    Linux查看进程运行的完整路径方法
  • 原文地址:https://www.cnblogs.com/cnblogsnearby/p/4767061.html
Copyright © 2020-2023  润新知