单调栈和单调队列

1,068 阅读1分钟

定义

  • 单调栈定义:单调栈的本质还是一个栈,具备栈的性质,只不过在栈的基础上有添加了一个性质,单调栈内的元素都是有序的(升序或降序);
  • 单调队列定义:单调队列使用的是双端队列,双端队列在队列的两端都可以插入和删除元素,在双端队列的基础上有添加了一个性质,单调队列内的元素都是有序的(升序或降序);

单调栈的应用

  1. 寻找数组中每个数左边第一个比它小的数,使用单调递增栈;
  2. 寻找数组中每个数左边第一个比它大的数,使用单调递减栈;
  3. 寻找数组中每个数右边第一个比它小的数,使用单调递增栈;
  4. 寻找数组中每个数右边第一个比它大的数,使用单调递减栈;

代码

寻找每个数左边第一个比他小的数,使用单调递增的栈;

int a[N];
stack<int> sta;
for(int i=0;i<n;i++)
{
    while(!sta.empty()&&sta.top()>=a[i])//由于需要单调递增,所以需要判断
    {                             //当前元素比栈顶元素小,需要出栈。
        sta.pop();
    }
    if(sta.empty()) cout<<-1<<" ";
    else cout<<sta.top()<<" ";//当所有比当前元素大的所有栈顶元素全部出栈后,							
    						//栈顶元素就是答案
	sta.push(a[i]);           
}

单调队列的应用

  • 求数组中每个长度为k区间的最小值或最大值;
  • 求最小值使用单调递增序列;求最大值使用单调递减序列。

代码

求数组中每个长度为k区间的最小值

int a[N];
deque<int> q;//保存元素的下标
for(int i=0;i<n;i++)
{
    if(i-q.front()>=k) q.pop_front(); //判断队头元素的位置和当前位置差距是否小于k
    while(!q.empty()&&a[q.back()]>=a[i]) q.pop_back();//如果队尾元素大于当前元素 则出队列。
    q.push_back(i);
    if(i>=k-1) cout<<a[q.front()]<<" ";//如果区间元素大于k个,开始输出。
}