前言
单调队列是维护一段区间内的最大或最小值的数据结构,一般和滑动窗口结合使用。
一、经典用法
1.模板——滑动窗口最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n=nums.size();
deque<int>index;
vector<int>ans(n-k+1,0);
for(int i=0;i<k-1;i++)
{
while(!index.empty()&&nums[index.back()]<=nums[i])
{
index.pop_back();
}
index.push_back(i);
}
for(int l=0,r=k-1;l<n-k+1;l++,r++)
{
while(!index.empty()&&nums[index.back()]<=nums[r])
{
index.pop_back();
}
index.push_back(r);
ans[l]=nums[index.front()];
if(index.front()==l)
{
index.pop_front();
}
}
return ans;
}
};
单调队列实际上是个双端队列。队列内元素按单调性排列,每出现一个新数就让队尾的元素和它比较,不符合单调性的就从尾出,以此保证队首元素总是区间内最值。
首先先把窗口扩到k长度,因为要求最大值,所以让队列从队首到队尾按从大到小排列。之后每次取队首元素作为答案即可,注意若队首元素就是当前窗口左侧值,则在窗口滑动前需要弹出队首。
2.绝对差不超过限制的最长连续子数组
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int n=nums.size();
deque<int>maxIndex;
deque<int>minIndex;
int ans=0;
for(int l=0,r=0;l<n;l++)
{
while(r<n&&ok(limit,nums[r],nums,maxIndex,minIndex))
{
push(r++,nums,maxIndex,minIndex);
}
ans=max(ans,r-l);
pop(l,maxIndex,minIndex);
}
return ans;
}
bool ok(int limit,int num,vector<int>&nums,deque<int>&maxIndex,deque<int>&minIndex)
{
int