目录
一,单调栈
二,具体实现
三,应用
数组大小关系计算
力扣 155. 最小栈
力扣 907. 子数组的最小值之和
力扣 716. 最大栈
力扣 84. 柱状图中最大的矩形
单调栈是一种基于栈进行的算法。
场景:
给定一个n个数的数组和一个空栈,依次读取n个数,每个数分别入栈一次,出栈一次,最后仍然是空栈。
在这个过程中,需要保持栈里面的元素从栈顶到栈底一直是单调递增(或递减)的,相应的,按照出栈顺序排列的n个数也是单调递增(或递减)的。
n个数的入栈顺序是原数组顺序,但是出栈顺序就不一定了,这个算法就是用来控制,何时入栈,何时出栈。
这一小部分内容来自单调栈_lucky52529的博客
现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。
10入栈时,栈为空,直接入栈,栈内元素为10。
3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。
7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。
4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。
12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。
ACM模板 这里面的firstInLeft函数就是用单调栈实现的,并且我做了封装,所以很多OJ题目原本要手写单调栈,有了我的模板就可以直接用了。
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
提示:
各函数的调用总次数不超过 20000 次
class MinStack {
public:
stacks;//主栈
stackm;//单调栈
MinStack() {
}
void push(int x) {
s.push(x);
if(m.empty()||m.top()>=x)m.push(x);
}
void pop() {
if(m.top()==s.top())m.pop();
s.pop();
}
int top() {
return s.top();
}
int min() {
return m.top();
}
};
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
输入:[3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
提示:
1 <= A <= 30000
1 <= A[i] <= 30000
//翻转vector
template
vector frev(vector v)
{
vector ans;
for(int i=v.size()-1;i>=0;i--)ans.push_back(v[i]);
return ans;
}
//vector乘一个数
template
void fcheng(vector &v,int n)
{
for(int i=v.size()-1;i>=0;i--)v[i]*=n;
}
//vector加一个数
template
void fjia(vector &v,int n)
{
for(int i=v.size()-1;i>=0;i--)v[i]+=n;
}
//返回vector每个数前面最近的比它小的数的ID,-1 或者 0到size-1
template
vector fminlef(vector v)
{
vector ans;
if(v.size()==0)return ans;
stackst;
st.push(0);
ans.push_back(-1);
for(int i=1;i=v[i])st.pop();
if(st.empty())ans.push_back(-1);
else ans.push_back(st.top());
st.push(i);
}
return ans;
}
//返回vector每个数后面最近的比它小的数的ID,size 或者 0到size-1
template
vector fminrig(vector v)
{
vectorv1=frev(v),v2=fminlef(v1);
fcheng(v2,-1);
fjia(v2,v.size()-1);
return frev(v2);
}
//返回vector每个数前面最近的比它小或等于的数的ID,-1 或者 0到size-1
template
vector fminlef2(vector v)
{
vector ans;
if(v.size()==0)return ans;
stackst;
st.push(0);
ans.push_back(-1);
for(int i=1;iv[i])st.pop();
if(st.empty())ans.push_back(-1);
else ans.push_back(st.top());
st.push(i);
}
return ans;
}
//返回vector每个数后面最近的比它小或等于的数的ID,size 或者 0到size-1
template
vector fminrig2(vector v)
{
vectorv1=frev(v),v2=fminlef2(v1);
fcheng(v2,-1);
fjia(v2,v.size()-1);
return frev(v2);
}
class Solution {
public:
int sumSubarrayMins(vector& A) {
vectorv1=fminlef(A),v2=fminrig2(A);
int ans=0;
for(int i=0;i
716. 最大栈
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
提示:
1 <= heights.length <=105
0 <= heights[i] <= 104
class Solution {
public:
int largestRectangleArea(vector& heights) {
vector id = Fminlef(heights),id2 = Fminrig(heights);
int ans = 0;
for (int i = 0; i < heights.size(); i++) {
ans = max(ans, (id2[i] - id[i]-1) * heights[i]);
}
return ans;
}
};