单调栈与单调队列

徘徊边缘 提交于 2020-01-31 00:52:48

版权声明:本文为CSDN博主「Alex_McAvoy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011815404/article/details/86896303

【单调栈】

1.原理

单调栈,就是栈内元素保持一定单调性(单调递增或单调递减)的栈,即从栈底到栈顶单调递增或递减。

对于单调递增的栈,如果栈为空或入栈元素值大于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素大的元素全部出栈。

对于单调递减的栈,如果栈为空或入栈元素值小于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素小的元素全部出栈。

2.应用

单调栈常用的应用有:

  1. 给定一组数,对于某个数,找到从左/右遍历第一个比它小/大的元素的位置
  2. 给定一组数,针对每个数,寻找其与其左/右第一个比它小/大的数之间有多少个数
  3. 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大
  4. 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大

3.实现

1)单调递增栈

stack<int> S;

for(int i = 1; i <= n; i++)
{
	//栈不为空且栈顶元素大于入栈元素时
    while(!S.empty() && a[S.top()]>a[i])
	{
        S.pop();	//将栈顶大于入栈元素的元素出栈
        ...			//更新结果
    }
    S.push(i);		//元素入栈
}

2)单调递减栈

stack<int> S;

for(int i = 1; i <= n; i++)
{
	//栈不为空且栈顶元素小于入栈元素时
    while(!S.empty() && a[S.top()]<a[i])
	{
        S.pop();	//将栈顶小于入栈元素的元素出栈
        ...			//更新结果
    }
    S.push(i);		//元素入栈
}

【单调队列】

1.原理

单调队列就是从队首到队尾满足单调性的队列,与单调栈极其相似,其基本原理与单调栈相同,只需将单调栈先进后出的性质改为先进先出的性质即可。

对于单调递增的队列,若队列为空或入队元素 xx 大于等于队尾元素,则入队;否则,入队会破坏队列的单调性,因此需要将队尾中比入队元素 xx 大的元素全部出队。

对于单调递减的队列,若队列为空或入队元素 xx 小于等于队尾元素,则入队;否则,入队会破坏队列的单调性,因此需要将队尾中比入队元素 xx 小的元素全部出队。

2.应用

单调队列的常用应用有:

  1. 给出一组数,求这组数中第一个大/小于等于一个数 xx 的数
  2. 维护单调性,从而解决区间内最小/大的问题
  3. 解决滑动窗口问题
  4. 优化多重背包 DP、斜率优化 DP

3.实现

单调队列一般使用 STL 的 deque(双端队列) 实现即可,由于双端队列即可再队首操作又可在队尾操作,那么这样的性质就弥补了单调栈只可在尾端操作的不足,使得首段也有了一定的限制。

1)单调递增队列

deque<int> Q;	//双端队列

for(int i = 1; i <= n; i++)
{
	//队列不为空且队尾元素大于入队元素时
    while((!Q.empty()) && Q.back()>A[i])
	{
       Q.pop_back();	//将队列尾端大于入队元素的元素出队
       ...				//更新结果
    }
    q.push_back(A[i]);	//元素入队
    ...					//更新结果
}

2)单调递减队列

deque<int> Q;			//双端队列

for(int i = 1; i <= n; i++)
{
	//队列不为空且队尾元素小于入队元素时
    while((!Q.empty()) && Q.back()<A[i])
	{
       Q.pop_back();	//将队列尾端小于入队元素的元素出队
       ...				//更新结果
    }
    q.push_back(A[i]);	//元素入队
    ...					//更新结果
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!