单调栈

目录

一,单调栈

二,具体实现

三,应用

数组大小关系计算

力扣 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题目原本要手写单调栈,有了我的模板就可以直接用了。

力扣 155. 最小栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 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();
    }
};

力扣 907. 子数组的最小值之和

给定一个整数数组 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. 最大栈

716. 最大栈

力扣 84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

单调栈_第1张图片

 

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:

单调栈_第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;
	}
};

你可能感兴趣的:(c++)