算法之单调栈
注意:单调栈是一种数据结构,并非是一种算法,但是我们做一些算法题的时候,这种单调性结构有妙用,所以我姑且放在算法篇进行讲解
单调栈
概念:
- 单调栈是一种数据结构,但是因为经常使用就将其放入算法
- 单调栈就是栈内的元素呈单调递增或者单调递减的(一般指栈顶到栈底)
- 将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素。
- 例如:例如,单调递增栈中自顶向下的元素为{0,11,45,81},插入元素14时为了保持单调性需要依次弹出0、11,操作后栈变为{14,45,81}
- 时间复杂度为
O(n)
适用场景:
-
单调栈可以求解出某个元素左边或者右边第一个比它大或者小的元素
-
可以将其分为具体四种问题:
- 寻找左侧第一个比当前元素大的元素
- 寻找左侧第一个比当前元素小的元素
- 寻找右侧第一个比当前元素大的元素
- 寻找右侧第一个比当前元素小的元素
各问题解决做法:
总结
:
- 查找比当前大的元素用单调递增栈,查找比当前小的元素用单调递减栈
- 从左侧查找就看插入栈时的栈顶元素,从右侧查找就看弹出栈时即将插入的元素
-
寻找左侧第一个比当前元素大的元素
:- 构造一个单调递增栈(从栈顶到栈底)
- 从左到右遍历元素
- 如果当前元素大于栈顶元素,则将其加入(也就是将栈里面小于当前元素的都弹出再插入);
- 如果小于,则当前栈顶元素就是当前遍历的元素左侧第一个比它大的元素
- 如果插入时的栈为空,则说明左侧不存在比当前元素大的元素
-
寻找左侧第一个比当前元素小的元素
:- 构造一个单调递减栈(从栈顶到栈底)
- 从左到右遍历元素
- 如果当前元素小于栈顶元素,就加入栈中
- 如果大于,则当前栈顶元素就是当前遍历元素左侧第一个比它小的元素
- 如果插入时的栈为空,则说明左侧不存在比当前元素小的元素
-
寻找右侧第一比当前元素大的元素
:- 构造一个单调递增栈(从栈顶到栈底)
- 从左到右遍历元素
- 如果当前遍历元素大于当前栈底元素,则当前栈顶元素的右侧第一个比它大的元素就是当前遍历元素
- 如果小于,则将其加入栈中
- 如果在栈中的元素没有被弹出,说明栈中剩下的元素没有右侧比它大的元素
-
寻找右侧第一个比当前元素小的元素
:- 构造一个单调递减栈(从栈顶到栈底)
- 从左到右遍历元素
- 如果当前遍历元素小于当前栈顶元素,则当前栈顶元素的右侧第一个比它小的元素就是当前遍历元素
- 如果大于,则加入栈中
- 如果在栈中的元素没有被弹出,说明栈中剩下的元素没有右侧比它小的元素
模板代码:
-
单调递增栈
int main(){stack<int>st;for(int i=0;i<nums.size();++i){while(!st.empty()&&nums[i]>nums[st.top()]){st.pop();}st.push(i);} }
-
单调递减栈
int main(){stack<int>st;for(int i=0;i<nums.size();++i){while(!st.empty()&&nums[i]<nums[st.top()]){st.pop();}st.push(i);} }