• 栈&单调栈


    后进先出

    数组模拟即可

    例1

    设计一个支持push,pop,top等操作并且可以在O(1)时间内检索出最小元素的堆栈

    显然一个栈维护最小值时,pop后无法O(1)知道其他最小值

    二叉堆是支持查最值的,但是O(logn)的

    所以我们可以建两个栈,一个栈存原数据,另一个维护从栈顶到now的min

    每次一起push ,pop 即可

    class MinStack {
    public:
        stack<int> ans,ans_min;
        MinStack() {
    
        }
        void push(int x) {
            ans.push(x);
            if (ans_min.empty() || ans_min.top()>x)
                ans_min.push(x);
            else
                ans_min.push(ans_min.top());
        }
        void pop() {
            ans.pop();
            ans_min.pop();
        }
        int top() {
            return ans.top();
        }
        int getMin() {
            return ans_min.top();
        }
    };
    

    例2:Editor

    中文https://www.acwing.com/problem/content/description/130/

    D,L,R 的时候要特判栈不空

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N=1e6+5;
    int m,x,top1,top2,L[N],R[N],f[N],sum;
    char a;
    inline int Max(int x,int y){return x>y?x:y;}
    int main(){
        while(scanf("%d",&m)!=EOF){
            top1=top2=sum=0;
    		f[0]=-0x7fffffff;
            while(m--){
                cin>>a;
                if(a=='I'){
                    scanf("%d",&x);
                    L[++top1]=x;
                    f[top1]=Max(f[top1-1],sum+=x);
                }
                if(a=='R'&&top2){
                    x=L[++top1]=R[top2--];
                    f[top1]=Max(f[top1-1],sum+=x);
                }
                if(a=='Q')scanf("%d",&x),printf("%d
    ",f[x]);
                if(a=='L'&&top1){
    				sum-=L[top1];
    				R[++top2]=L[top1--];
    			}
                if(a=='D'&&top1) sum-=L[top1--];
            }
        }
    }
    

    前缀中缀后缀表达式

      
    // 递归法求中缀表达式的值,O(n^2)
    int calc(int l, int r) {
    	// 寻找未被任何括号包含的最后一个加减号
    	for (int i = r, j = 0; i >= l; i--) {
    		if (s[i] == '(') j++;
    		if (s[i] == ')') j--;
    		if (j == 0 && s[i] == '+') return calc(l, i - 1) + calc(i + 1, r);
    		if (j == 0 && s[i] == '-') return calc(l, i - 1) - calc(i + 1, r);
    	}
    	// 寻找未被任何括号包含的最后一个乘除号
    	for (int i = r, j = 0; i >= l; i--) {
    		if (s[i] == '(') j++;
    		if (s[i] == ')') j--;
    		if (j == 0 && s[i] == '*') return calc(l, i - 1) * calc(i + 1, r);
    		if (j == 0 && s[i] == '/') return calc(l, i - 1) / calc(i + 1, r);
    	}
    	// 首尾是括号
    	if (s[l] == '('&&s[r] == ')') return calc(l + 1, r - 1);
    	// 是一个数
    	int ans = 0;
    	for (int i = l; i <= r; i++) ans = ans * 10 + s[i] - '0';
    	return ans;
    }
    
    // ----------------------------------------------------
    // 后缀表达式转中缀表达式,同时求值,O(n)
    
    // 数值栈 
    vector<int> nums; 
    // 运算符栈 
    vector<char> ops;
    
    // 优先级 
    int grade(char op) {
    	switch (op) {
    	case '(':
    		return 1;
    	case '+':
    	case '-':
    		return 2;
    	case '*':
    	case '/':
    		return 3;
    	}
    	return 0;
    }
    
    // 处理后缀表达式中的一个运算符 
    void calc(char op) {
    	// 从栈顶取出两个数 
    	int y = *nums.rbegin();
    	nums.pop_back();
    	int x = *nums.rbegin();
    	nums.pop_back();
    	int z;
    	switch (op) {
    	case '+':
    		z = x + y;
    		break;
    	case '-':
    		z = x - y;
    		break;
    	case '*':
    		z = x * y;
    		break;
    	case '/':
    		z = x / y;
    		break;
    	}
    	// 把运算结果放回栈中 
    	nums.push_back(z);	
    }
    
    // 中缀表达式转后缀表达式,同时对后缀表达式求值 
    int solve(string s) {
    	nums.clear();
    	ops.clear();
    	int top = 0, val = 0;
    	for (int i = 0; i < s.size(); i++) {
    		// 中缀表达式的一个数字 
    		if (s[i] >= '0' && s[i] <= '9') {
    			val = val * 10 + s[i] - '0';
    			if (s[i+1] >= '0' && s[i+1] <= '9') continue;
    			// 后缀表达式的一个数,直接入栈 
    			nums.push_back(val);
    			val = 0;
    		}
    		// 中缀表达式的左括号 
    		else if (s[i] == '(') ops.push_back(s[i]);
    		// 中缀表达式的右括号 
    		else if (s[i] == ')') {
    			while (*ops.rbegin() != '(') {
    				// 处理后缀表达式的一个运算符 
    				calc(*ops.rbegin());
    				ops.pop_back();
    			}
    			ops.pop_back();
    		}
    		// 中缀表达式的加减乘除号 
    		else {
    			while (ops.size() && grade(*ops.rbegin()) >= grade(s[i])) {
    				calc(*ops.rbegin());
    				ops.pop_back();
    			}
    			ops.push_back(s[i]);
    		} 
    	}
    	while (ops.size()) {
    		calc(*ops.rbegin());
    		ops.pop_back();
    	}
    	// 后缀表达式栈中最后剩下的数就是答案 
    	return *nums.begin();
    }
    
    

    单调栈

    利用单调栈,可以找到从左/右遍历第一个比它小/大的元素的位置

    模板

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=3000006;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n;
    int f[N],ans[N],s[N],top;
    int main() {
    	n=read();
    	for(int i=1;i<=n;i++) f[i]=read();
    	for(int i=n;i;i--) {
    		while(top&&f[s[top]]<=f[i]) top--;
    		ans[i]=s[top];
    		s[++top]=i;
    	}
    	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    	return 0;
    }
    
    

    最大矩形面积

    栈里保存矩形,矩形高度递增,

    从左到右扫描,遇到比st[top]高的矩阵就入栈,令w[top]=1

    否则不断弹出比st[top]小的,然后累加width更新ans,直到遇到比st[top]高的矩阵或栈空就入栈,然后令w[top]=width+1(继承前面的宽度)

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int N=100005;
    long long max(long long x,long long y){return x<y?y:x;}
    int n,a[N];
    int s[N],top,w[N];
    long long ans=0;
    int main() {
        while(1){
            ans=0;
            memset(w,0,sizeof(w));
            scanf("%d",&n);
            if(!n) return 0;
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            a[n+1]=0;
            for(int i=1;i<=n+1;i++) {
                if(a[i]>s[top])
                    s[++top]=a[i],w[top]=1;
                else {
                    int width=0;
                    while(a[i]<s[top]) {
                        width+=w[top];
                        ans=max(ans,(long long)width*s[top]);
                        top--;
                    }
                    s[++top]=a[i];w[top]=width+1;
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Ignatius and the Princess IV
    JavaFX+SpringBoot+验证码功能的小型薪酬管理系统
    JFX11+Maven+IDEA 发布跨平台应用的完美解决方案
    一个开源的跨平台音乐播放与音乐下载器
    JavaFX获取屏幕尺寸
    OkHttp:NoClassDefFoundError
    jasypt-spring-boot提示Failed to bind properties
    JFX11+IDEA跨平台打包发布的完美解决办法
    IDEA通过Maven打包JavaFX工程(OpenJFX11)
    IDEA 配置文件位置
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13536051.html
Copyright © 2020-2023  润新知