【算法竞赛进阶指南】0x11 栈

news2024/11/29 2:57:51

0x11 栈

基础应用

两个栈维护前面区间的最小元素

41. 包含min函数的栈 - AcWing题库

可以开个小根堆维护最小值,但是这样时间是logN的。如果只用一个变量来存,一旦出现了出栈操作就无从下手了。因此用一个线性结构来保存每个历史时刻的最小值。

开两个栈,一个用来存数据,一个记录当前最小值。

有数据入栈,就把这个数据与minn栈栈顶做对比决定是否入栈。出栈也做个对比即可维护这样一个数据结构。

class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> st;
    stack<int> minn;
    MinStack() {
        
    }
    
    void push(int x) {
        st.push(x);
        if(minn.empty()||minn.top()>=x) minn.push(x);
    }
    
    void pop() {
        if(st.top()==minn.top()) minn.pop();
        st.pop();
    }
    
    int top() {
        return st.top();
    }
    
    int getMin() {
        return minn.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

序列中修改某个指定位置

始终在序列中间,某个指定位置进行修改,就可以用两个栈,类似于对顶堆用对顶栈来维护。

128. 编辑器 - AcWing题库

#include<bits/stdc++.h>
using ll=long long;
#define int ll
const int N=1e6+10;
const int M=1e5+10;
int q;
int s[N],m[N];
std::stack<int> l,r;
void solve()
{
	std::cin>>q;
	m[0]=-2e9;
	while(q--)
	{
		char op;
		std::cin>>op;
		//getchar();
		int x;
		if(op=='I')
		{
			std::cin>>x;
			l.push(x);
			s[l.size()]=s[l.size()-1]+x;
			m[l.size()]=std::max(m[l.size()-1],s[l.size()]);
			
		}else if(op=='D'&&l.size()){
			l.pop();
			
		}else if(op=='L'&&l.size()){
			r.push(l.top());
			l.pop();
			
		}else if(op=='R'&&r.size()){//光标右移 
			x=r.top();
			r.pop();
			l.push(x);
			
			s[l.size()]=s[l.size()-1]+x;
			m[l.size()]=std::max(m[l.size()-1],s[l.size()]);
		}else if(op=='Q'){
			
			std::cin>>x;
			std::cout<<m[x]<<'\n';
		}
	}
}
signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t=1;
	//std::cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
} 

值得注意的是开了ios之后就不要用getchar()这类c的输入了。

入栈顺序一定,求可能的出栈情况(数学题,后面补)

129. 火车进栈 - AcWing题库

dfs枚举O(2^{n})

这题要求输出每种可能的出栈顺序,因为这里n<20。

dfs枚举,对于每一个状态,我们只有两种选择:

1入栈

2出栈

#include<bits/stdc++.h>
using ll=long long;
const int N=2e5+10;
int n;
std::vector<int> ans; 
std::stack<int> st;
int cnt;
void dfs(int x)
{
	if(cnt>=20) return ;
	if(ans.size()>=n)//全都出栈了 
	{
		cnt++;
		for(auto i:ans) std::cout<<i;
		std::cout<<'\n';
		return ;
	}
	if(st.size())//如果栈里还有元素 
	{//考虑出栈 
		ans.push_back(st.top());
		st.pop();
		dfs(x);
		st.push(ans.back());
		ans.pop_back();	
	}	
	if(x<=n)//还能入栈 
	{
		st.push(x);
		dfs(x+1);
		st.pop();
	}
} 
void solve()
{
	std::cin>>n;
	dfs(1);
}
signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t=1;
	//std::cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
} 
 递推O(n)

130. 火车进出栈问题 - AcWing题库

这个问题只关心方案数并不关心具体的方案。数据是60000,暴力枚举肯定是不行的。

表达式求值

后缀表达式求值

1.如果遇到一个数就把这个数入栈

2.遇到运算符就弹出栈中两个元素进行运算,把结果入栈

3.扫描完成后,栈中只剩一个数,就是表达式的值

中缀表达式求值

如果想让计算机求解中缀表达式,最快的方法就是把中缀表达式转化成后缀表达式。这个转化过程可以用栈O(N)完成。

1.建立一个存运算符的栈,逐一扫描中缀表达式的元素。

        1)遇到一个数就输出

        2)左括号入栈

        3)右括号,不断出栈并输出直到栈顶为左括号,然后左括号出栈。

        4)遇到运算符,只要栈顶符号优先级不低于新符号就不断出栈,最后把新符号入栈。乘除>加减>左括号。

 2.依次取出并输出栈中所有剩余符号,最终输出的序列就是一个与原中缀表达式等价的后缀表达式。

 也可以递归直接求解,时间复杂度O(N)。

中缀表达式的递归法求值

求解中缀表达式s[1~N]的值

1.在L~R中考虑没有被任何括号包含的运算符

1)若存在加减号,选最后一个,分成左右两半递归,结果相加减,返回。

2)若存在乘除号,选最后一个,分成左右两半递归,结果相乘除,返回。

2.所有运算符都被括号包含

1)首尾字符是括号,递归求解S[L+1~R-1],把结果返回

2)否则,说明区间S[L~R]是一个数,直接返回数值

单调栈

131. 直方图中最大的矩形 - AcWing题库

因为最大矩形只与高和宽有关系,因此我们可以对每个点,求出以它为高的最小左边界和最大右边界。那么这个问题就变成了,找出左边第一个比它小的坐标,右边第一个比它小的坐标。最后枚举每个点,计算面积枚举最大值即可。

找到左边第一个小/大,这是一个经典的单调栈问题。我们对左右两边各做一次就好。

#include<bits/stdc++.h>
using ll=long long;
const int N=1e5+10;
int n;
int h[N],l[N],r[N];
std::stack<int> sl,sr;
ll ans=-1;
void solve()
{
	while(std::cin>>n&&n!=0) 
	{
		for(int i=1;i<=n;i++)	std::cin>>h[i];
		
		h[0]=-1,h[n+1]=-1;
		
		//找左边第一个小的
		sl.push(0);//存下标 
		for(int i=1;i<=n;i++)
		{
			while(sl.size()&&h[sl.top()]>=h[i]) sl.pop();
			l[i]=sl.top();
			sl.push(i);	
		} 
		
		sr.push(n+1);
		for(int i=n;i>=1;i--)
		{
			while(sr.size()&&h[sr.top()]>=h[i]) sr.pop();
			r[i]=sr.top();
			sr.push(i);	
		} 
		
		ans=0;
		for(int i=1;i<=n;i++)
		{
			ans=std::max(ans,(ll)h[i]*(r[i]-l[i]-1));
		}
		std::cout<<ans<<'\n';
	}
}
signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t=1;
	//std::cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
} 

练习

给定入栈顺序,判定出栈顺序是否合法

946. 验证栈序列 - 力扣(LeetCode)

LCR 148. 验证图书取出顺序 - 力扣(LeetCode)这两题完全一样。

对每个应该入栈的元素入栈,同时比较栈顶元素和当前应该出栈的元素是否相同,相同就出栈。如果最后栈空说明可以,不空就不行。

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        std::stack<int> st;
        int j=0;
        for(auto i:pushed)
        {
            st.push(i);
            while(st.size()&&st.top()==popped[j])
            {
                st.pop();
                j++;
            }
        }
        if(st.size()) return false;
        else return true;
    }
};

给定入栈顺序,求出字典序最大的出栈顺序

A-栈和排序_2021秋季算法入门班第四章习题:堆栈队列单调栈等 (nowcoder.com)

思想就是比较当前栈顶元素比后面待入栈的元素都要大了,就要输出,否则我们就可以等到后面入栈的时候再输出。

#include<bits/stdc++.h>
using ll=long long;
const int N=1e6+10;
int n;
int a[N],m[N];
std::stack<int> st;
void solve()
{
	int n;
	std::cin>>n;
	for(int i=1;i<=n;i++)
	{
		std::cin>>a[i];
	}
	//求出后缀最大值
	for(int i=n;i>=1;i--)
	{
		m[i]=std::max(m[i+1],a[i]);
	} 
	for(int i=1;i<=n;i++)
	{
		st.push(a[i]);
		while(st.size()&&st.top()>m[i+1])
		{
			std::cout<<st.top()<<" ";
			st.pop();
		}
	}
	while(st.size())
	{
		std::cout<<st.top()<<" ";
		st.pop();
	}
}
signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int t=1;
	//std::cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
} 

给定后缀表达式计算结果

B-牛牛与后缀表达式_2021秋季算法入门班第四章习题:堆栈队列单调栈等 (nowcoder.com)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 给定一个后缀表达式,返回它的结果
     * @param str string字符串 
     * @return long长整型
     */
    stack<long long> st;
    long long legalExp(string str) {
        // write code here
        int flag=0;
        long long num=0;
        for(auto i:str)
        {
            if(i>='0'&&i<='9')
            {
                num=num*10+i-'0';
            }else if(i=='#'){
                st.push(num);
                num=0;
            }else{//运算符
                long long a=st.top();
                st.pop();
                long long b=st.top();
                st.pop();
                if(i=='+') num=a+b;
                else if(i=='-') num=b-a;
                else num=a*b;
                st.push(num);
                num=0;
            }
        }
        return st.top();
    }
};

判断一个字符串能否由“ab“不停插入得到

C-好串_2021秋季算法入门班第四章习题:堆栈队列单调栈等 (nowcoder.com)

类似于括号匹配问题,可以把a看作左括号,b看作右括号。每遇到一个b就去弹出一个a。

#include<bits/stdc++.h>
std::string s;
std::stack<char> st;
void solve()
{
    std::cin>>s;
    for(auto i:s)
    {
        if(i=='a') st.push(i);
        else{
            if(st.empty()||st.top()!='a') 
            {
                std::cout<<"Bad"<<'\n';
                return ;
            }
            st.pop();
        }
    }
    if(st.size()) std::cout<<"Bad"<<'\n';
    else std::cout<<"Good"<<'\n';
}
signed main()
{
    int t=1;
    //std::cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1560089.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3封装Element分页

配置当前页 配置每页条数 页面改变、每页条数改变都触发回调 封装分页 Pagination.vue <template><el-paginationbackgroundv-bind"$attrs":page-sizes"pageSizes"v-model:current-page"page"v-model:page-size"pageSize":t…

常用字符串函数及模拟实现

1.strlen() 用法:求字符串长度 size_t strlen(const char *Str) 参数:字符串的起始地址,可以传地址也可以直接传一个字符串 返回值:字符串长度 模拟实现: 自己实现求字符串长度的函数(三种方法)-CSDN博客 2.strcpy() 用法:拷贝字符串 char* strcpy(char*_Destination,co…

【PduR路由】IPduM模块详细介绍

目录 1.IpduM功能简介 2.IpduM模块依赖的其他模块 2.1RTE (BSW Scheduler) 2.2PDU Router 2.3COM 3.IpduM功能详解 3.1 功能概述 3.2 I-PDU多路复用I-PDU Multiplexing 3.2.1 Definitions and Layout 3.2.2通用功能描述 General 3.2.3模块初始化 Initialization 3.…

fpga_awb

色温: sesor原始图像中的白色如果不经AWB处理&#xff0c;在高色温(如阴天)下偏蓝&#xff0c;在低色温下偏黄。 引入白平衡算法 而AWB的核心就是调整图像色温&#xff0c;使得摄像头采集的图像更加真实&#xff0c;达到人眼观察的效果。 白平衡一般通过调节传感器输出图像RGB…

CCF-CSP19<2020-06>-第1/2题

202006-1 线性分类器 题目&#xff1a;202006-1 题目分析&#xff1a; 给定n个点&#xff0c;并标记为AB两类&#xff0c;问给定直线是否能将其分为两个点集。 简单数学知识&#xff0c;点在直线上满足axbyc0&#xff0c;点在直线割平面所得的上下其值会正负相反。 AC代码…

信息安全技术基础知识总结

一、信息安全基础知识 信息安全基本要素&#xff1a; 1. 机密性&#xff08;C&#xff09;&#xff1a;确保信息不暴露给未授权的实体或进程 2. 完整性&#xff08;I&#xff09;&#xff1a;只有得到允许的人才能修改数据&#xff0c;并且能够判别出数据是否已被篡改 3. 可用性…

大话设计模式之外观模式

外观模式&#xff08;Facade Pattern&#xff09;是一种软件设计模式&#xff0c;旨在提供一个简单的接口&#xff0c;隐藏系统复杂性&#xff0c;使得客户端能够更容易地使用系统。这种模式属于结构型模式&#xff0c;它通过为多个子系统提供一个统一的接口&#xff0c;简化了…

docker无脑部署zabbix6.0+agent

文章目录 前言一、安装docker-compose二、部署Zabbix Server 6.0agent1.创建父目录2.拉取镜像3.编辑docker-compose.yml文件 二、浏览器访问Zabbix1.url栏输入http://ip/2.修改主机配置 总结 前言 随着监控的不断发展&#xff0c;zabbix这门技术也越来越重要&#xff0c;很多人…

PVE设置显卡直通(二:Linux显卡直通,以及Linux系统下安装cuda库)

PVE设置显卡直通(一:硬件设置) 本文仅记录PVE关于Linux下的显卡直通步骤 例程不过多阐述 ps: 无直通经验的同学,先参阅 PVE设置显卡直通(一:硬件设置),再参阅本博文 参阅完成 PVE设置显卡直通(一:硬件设置)后,直接在PVE面板中添加显卡硬件到自己的主机即可,此文中…

【Java与数学】若不等式x^2-a*x+a<0的解集中恰有3个整数,求a的范围?

【分析】 既然不等式存在解集&#xff0c;说明一元二次方程x^2-a*xa0有解&#xff1b; 解之间横跨三个整数&#xff0c;说明Δ大于0&#xff1b; 三个整数必然是连续的&#xff0c;因为f(x)x^2-a*xa最多只与x轴存在两个交点&#xff0c;这是题设里的隐含条件。 【传统解法】…

C++项目——集群聊天服务器项目(十)点对点聊天业务

本节来实现C集群聊天服务器项目中的点对点聊天业务&#xff0c;一起来试试吧 一、点对点聊天业务 聊天服务器中一个重要的功能就是实现点对点聊天&#xff0c;客户端发送的信息包含聊天业务msgid、自身 的id和姓名、聊天对象的id号以及聊天信息&#xff0c;例如&#xff1a; …

C语言TCP服务器模型 : select + 多线程与双循环单线程阻塞服务器的比较

观察到的实验现象: 启动三个客户端: 使用双循环阻塞服务器:只能accept后等待收发,同时只能与一个客户端建立连接,必须等已连接的客户端多次收发 明确断开后才能与下个客户端连接 使用IO多路复用select:可以同时接收所有的连接请求,并且连接状态一直是存活的,直到客户端关闭连…

离散数学--谓词逻辑之复习与前束范式与谓词演算的推理理论

引子&#xff1a;在命题演算中&#xff0c;常常要化成规范形式&#xff0c;对于谓词的演算&#xff0c;可以化成与他等价的范式&#xff01; 前束范式定义&#xff1a; 一个公式&#xff0c;如果量词均非否定地在全式的开头&#xff0c;它们的作用域延伸到整个公式的末尾&…

八、大模型之Fine-Tuning(1)

1 什么时候需要Fine-Tuning 有私有部署的需求开源模型原生的能力不满足业务需求 2 训练模型利器Hugging Face 官网&#xff08;https://huggingface.co/&#xff09;相当于面向NLP模型的Github基于transformer的开源模型非常全封装了模型、数据集、训练器等&#xff0c;资源…

工作究竟是谁的?

在近两年的就业环境中&#xff0c;普遍存在着挑战与不确定性&#xff0c;许多人追求的是一种稳定的工作和收入来源。在这样的背景下&#xff0c;我们来探讨一个核心问题&#xff1a;工作的归属是谁的&#xff1f; 根据《穷爸爸富爸爸》中提出的ESBI四象限理论&#xff0c;我们可…

【经典算法】LeetCode14:最长公共前缀(Java/C/Python3实现含注释说明)

最长公共前缀 题目思路及实现方式一&#xff1a;横向扫描思路代码实现Java版本C语言版本Python3版本 复杂度分析 方式二&#xff1a;纵向扫描思路代码实现Java版本C语言版本Python3版本 复杂度分析 方式三&#xff1a;分治思路代码实现Java版本C语言版本Python3版本 复杂度分析…

单元测试mockito(一)

1.单元测试 1.1 单元测试的特点 ●配合断言使用(杜绝System.out) ●可重复执行 。不依赖环境 ●不会对数据产生影响 ●spring的上下文环境不是必须的 ●一般都需要配合mock类框架来实现 1.2 mock类框架使用场景 要进行测试的方法存在外部依赖(如db,redis,第三方接口调用等),为…

3.31学习总结

(本次学习总结,总结了目前学习java遇到的一些关键字和零碎知识点) 一.static关键字 static可以用来修饰类的成员方法、类的成员变量、类中的内部类&#xff08;以及用static修饰的内部类中的变量、方法、内部类&#xff09;&#xff0c;另外可以编写static代码块来优化程序性…

权限问题(Windows-System)

方法&#xff1a;用命令来写一个注册表的脚本 &#xff1f;System是最高级用户&#xff0c;但不拥有最高级权限 编写两文档&#xff1a;system.reg 和 remove.reg,代码如下&#xff1a; system.reg&#xff1a; Windows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\*…

YOLOv5改进 | 低照度检测 | 2024最新改进CPA-Enhancer链式思考网络(适用低照度、图像去雾、雨天、雪天)

一、本文介绍 本文给大家带来的2024.3月份最新改进机制&#xff0c;由CPA-Enhancer: Chain-of-Thought Prompted Adaptive Enhancer for Object Detection under Unknown Degradations论文提出的CPA-Enhancer链式思考网络&#xff0c;CPA-Enhancer通过引入链式思考提示机制&am…