c++滑动窗口与单调队列

 一、解决问题

             有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现窗口从左边开始
             向右滑动,每次滑动一个单位,求每次滑动后窗口中的最大值和最小值。

Window position Minimum value Maaximum value 
[1     3    -1]   -3     5     3     6     7 -1 3
 1    [3    -1    -3]    5     3     6     7 -3 3
1     3[   -1    -3     5]    3     6     7 -3 5
1     3    -1[   -3     5     3]    6     7 -3 5
1     3    -1    -3    [5     3     6]    7 3 6
1     3    -1    -3     5    [3     6     7] 3 7

朴素做法是对于每个窗口区间,从头到尾统计一遍区间的最值。这样操作的话,时
间复杂度为 O((n-k+1)∗k) ,最差情况 k = n/2 时,时间复杂度为 O(n^{2})

c++滑动窗口与单调队列_第1张图片

 二、单调队列

•单调性是一个数学概念,指函数在一个区间内,函数值随自变量的变化而保持单一性的变化。
•单调队列指队列内部元素从队首到队尾, 一直保持单调递增或单调递减 。(当然也可以保持单调不下降,允许相邻元素相等

三、正解 

建立一个单调递增队列,每个新元素从队尾入队,如果前方元素更大,则让前方元素出队,直至新元素排到合理位置。

 模板代码:

    单调队列代码模板(STL)

deque dq; // 用双端队列来实现单调队列
  
  for (int i = 1; i <= n; i++) { // i 代表滑动窗口右端点
  
    // 队首元素已经位于滑动窗口左边了,移除
    if (!dq.empty() && dq.front()+k == i) {
      dq.pop_front();
    }
    
    // 以单调(严格)递减队列为例,新入队元素必须小于队尾元素
    // 否则,删除队尾。(递增或严格递增类似)
    while(!dq.empty() && arr[dq.back()] <= arr[i]) {
      dq.pop_back();
    }
    
    // 压入队尾元素
    dq.push_back(i);
    
    if (i >= k) {
      // 这里处理队首元素,一般为区间最大或最小
      cout << arr[dq.front()] << endl;
    }
  }

单调队列代码模板(手写)

int q[2000002]; // 手写队列
int head = 1, tail = 0; // 手写队首尾指针
for (int i = 1; i <= n; i++) 
{

    // 队首元素已经位于滑动窗口左(外)边了,移除
    if (head <= tail && q[head] + k == i) 
    {
        head++;
    }

    // 以单调(严格)递减队列为例,新入队元素必须小于队尾元素
    // 否则,删除队尾。(递增或严格递增类似)
    while (head <= tail && arr[q[tail]] < arr[i]) 
    {
        tail--;
    }

    // 压入队尾元素
    q[++tail] = i;

    // 这里处理队首元素,一般队首为区间最大或最小
    if (i >= k) 
    {
        cout << arr[q[head]] << endl;
    }
}

单调队列代码模板(优先队列)

•	  // 以大根堆构建的优先队列, pair代表:值和位置
  priority_queue> pq;
  for (int i = 1; i <= n; i++) {
    
    // 将元素压入优先队列
    pq.push({arr[i],i});
    
    // 如果队首元素在窗口之外,丢弃
    while (pq.top().second + k <= i) {
      pq.pop();
    }
    
    // 处理队首元素
    if (i >= k) 
      cout << pq.top().first << '\n';
  }



P1886 滑动窗口 /【模板】单调队列

P2032 扫描

P1440 求m区间内的最小值

P2251 质量检测
 

你可能感兴趣的:(c++算法模版,算法)