前言:
①单调队列模板(左边是队头hh,右边是队尾tt)
首先维护两个指针hh和tt的位置
常见模型:找出滑动窗口中的最大值/最小值 int hh = 0, tt = -1; for (int i = 0; i < n; i ++ ) { while (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗口 while (hh <= tt && check(q[tt], i)) tt -- ; q[ ++ tt] = i; }
AcWing 154. 滑动窗口(模板题)--单调队列
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], q[N]; //q存idx
int n, k;
int main(){
cin >> n >> k;
for(int i = 0; i < n; i ++) cin >> a[i];
int hh = 0, tt = -1;
// Q1: 输出每个窗口中的最小值
for(int i = 0; i < n; i ++){ // 二重维护
// step1: 维护一下窗口长度不超过k(左边队头hh的位置!)
if(hh <= tt && i - k + 1 > q[hh]) hh ++;
// step2: 维护单调队列q是单调增的即可
while(hh <= tt && a[i] < a[q[tt]]) tt --;
q[++ tt] = i;
if (i + 1 >= k) // 只有当有了一个完整的窗口后才能进行输出
cout << a[q[hh]] << " ";
}cout << endl;
// Q2: 输出每个窗口中的最大值
hh = 0, tt = -1; // 别忘记要先重置
for(int i = 0; i < n; i ++){ // 二重维护
// step1: 维护一下窗口长度不超过k(左边队头hh的位置!)
if(hh <= tt && i - k + 1 > q[hh]) hh ++;
// step2: 维护单调队列q是单调减的即可
while(hh <= tt && a[i] > a[q[tt]]) tt --;
q[++ tt] = i;
if (i + 1 >= k)
cout << a[q[hh]] << " ";
}
}
Leetcode 3. 无重复字符的最长子串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.length(), res = 0;
unordered_set<int> Set; // 用于判断当前滑动窗口中存在字符情况
int l = 0, r = -1; // 类模板中的hh和tt(只不过这里不考虑单调性)
for (int i = 0; i < n; i ++){
while(l <= r && Set.count(s[i])){
l ++; // 维护出一个合法的单调队列,进行res更新
if(s[i] == s[l - 1]) break; // 剔除掉那个重复的词之后即完成了维护
else Set.erase(s[l - 1]); // 剔除非重复char需要在set中删除
}
r ++;
Set.insert(s[r]);
res = max(res, r - l + 1);
}
return res;
}
};