当前位置: 首页 > news >正文

【洛谷】【模板】栈、有效的括号、验证栈序列、后缀表达式、(stack相关算法题)

文章目录

  • 【模板】栈
    • 题目描述
    • 题目解析
    • 代码
  • 有效的括号
    • 题目描述
    • 题目解析
    • 代码
  • 验证栈序列
    • 题目描述
    • 题目解析
    • 代码
  • 后缀表达式
    • 题目描述
    • 题目解析
    • 代码
  • 括号序列
    • 题目描述
    • 题目解析
    • 代码


【模板】栈

题目描述

在这里插入图片描述

题目解析

这道题非常简单,唯一需要注意的是x的数据范围,我们知道无论是32位还是64位:
int 通常占 4 字节,取值范围为:(-2^31到2^31 - 1);
unsigned int也占 4 字节,取值范围为:(0到 2^32 - 1);
long long通常占 8字节,取值范围为:(-2^63到 2^63 - 1);
unsigned long long也占 8 字节,取值范围为:(0到 2^64 - 1);
所以这里我们使用unsigned long long就刚好符合题目对x数据范围的规定。

代码

因为本题不涉及复杂过程,推荐使用第二种方法用数组模拟栈,效率更高。

using namespace std;
#include <iostream>
#include <stack>typedef unsigned long long ULL;size_t T;
size_t n;int main()
{cin >> T;for (int i = 0; i < T; i++){cin >> n;stack<ULL> st;for (int j = 0; j < n; j++){string str;cin >> str;if (str == "push"){ULL x;cin >> x;st.push(x);}else if (str == "pop"){if (st.empty())cout << "Empty" << endl;elsest.pop();}else if (str == "query"){if (st.empty())cout << "Anguei!" << endl;elsecout << st.top() << endl;}else{cout << st.size() << endl;}}}return 0;
}//用数组模拟栈
using namespace std;
#include <iostream>typedef unsigned long long ULL;const int N = 1e6 + 10;
ULL st[N];
int T;
int n;int main()
{int top = 0; //指向栈顶cin >> T;for (int i = 0; i < T; i++){cin >> n;top = 0;  //一组数据开始之前先清楚原先栈的数据for (int j = 0; j < n; j++){string str;cin >> str;if (str == "push"){ULL x;cin >> x;st[++top] = x;}else if (str == "pop"){if (top == 0)cout << "Empty" << endl;else--top;}else if (str == "query"){if (top == 0)cout << "Anguei!" << endl;elsecout << st[top] << endl;}else{cout << top << endl; //数组是从下标1开始存的}}}return 0;
}

有效的括号

题目描述

在这里插入图片描述

题目解析

这道题思路很简单,看下面的代码注释。注意细节右两个:
1、遇到右括号时若栈为空,无法匹配,返回false。(例如只有一个右括号,返回false)
2、遍历完string出循环后需要判断栈是否为空,若为空表示全部元素匹配成功返回ture,否则返回false。(例如只有一个左括号,返回false)

代码

class Solution {
public:bool isValid(string s) {stack<char> st;for(auto e : s){//遇到左括号入栈if(e == '(' || e == '[' || e == '{')st.push(e);//遇到右括号与栈顶元素比较else{//若此时栈中无元素,无法匹配if(st.empty())return false;//匹配失败,返回falseelse if((e == ')' && st.top() != '(') || (e == ']' && st.top() != '[') || (e == '}' && st.top() != '{')) return false;//匹配成功,pop栈顶,继续循环比较else              st.pop();}}//若遍历完后若栈为空,返回true,否则falsereturn st.empty();}
};

验证栈序列

题目描述

在这里插入图片描述

题目解析

这道题很经典,思路就是创建一个栈来模拟验证入栈序列和出栈序列是否匹配,需要注意的点是模拟数组出栈,并判断出栈数据是否和出栈序列匹配时while循环的条件要加一个j >= n,避免出栈序列数组越界访问。

代码

using namespace std;
#include <iostream>
#include <stack>
#include <string>const int N = 1e5 + 10;
int push[N]; //存放入栈序列
int pop[N];  //存放出栈序列
int q;
int n;int main()
{cin >> q;//询问q轮while (q--){//根据输入创建入栈和出栈序列数组cin >> n; //系列长度for (int i = 1; i <= n; i++){cin >> push[i];}for (int i = 1; i <= n; i++){cin >> pop[i];}int j = 1; //j指向出栈序列下标stack<int> st;//遍历入栈序列验证和出栈序列是否匹配//i始终指向入栈序列下标for (int i = 1; i <= n; i++){//不管如何,先把数据入栈st.push(push[i]);//若此时栈顶数据和出栈序列下标为j的元素相等,开始出栈匹配while (!st.empty() && j <= n && st.top() == pop[j]) {//模拟数组出栈,并判断出栈数据是否和出栈序列匹配st.pop();++j;}}if (st.empty()){//匹配完后栈为空,表示匹配成功cout << "Yes" << endl;}else{//匹配完后栈不为空,表示匹配失败cout << "No" << endl;}}return 0;
}

后缀表达式

题目描述

在这里插入图片描述

题目解析

这道题也很经典,核心思路是遇到数字把数字入栈,遇到运算符弹出栈顶两个数字,栈顶数字当作左操作数,第二个数字当作右操作数,运算后把结果重新入栈。
但是这道题有一个细节,数值大小不是直接给的,而是给的一串字符串,需要我们自己从字符串中提取数字字符并转换为数值。解决这个思路有两种方法,第一种可能是大家最先想到的,先通过 numstr += e 拼接字符,遇到 . 后逆序遍历字符串,并通过位权计算数值,这种方法需要字符串动态扩容有额外开销,所以我们更推荐第二种方法,直接算术累积,这里会用到秦九韶算法的思想,它是一种高效计算多项式值的算法,运用到本道题的思路就是“前一次结果 × 10 + 当前位数字” ,下面小编以129为例给大家演示一下:

在这里插入图片描述

代码

//思路1
using namespace std;
#include <iostream>
#include <stack>
#include <string>int main()
{string str;cin >> str;stack<int> st;string numstr; //暂存数字字符串for (auto e : str){//若遇到数字字符把数字字符存到numstrif(e >= '0' && e <= '9'){//numstr += e;}//若遇到'.',把数字字符串转化为数字入栈,并把numstr置空else if (e == '.'){int num = 0;  //转化后入栈数字int quan = 1; //位权//从个位开始遍历numstr,个位权为1,十位权为10,依次类推//计算前需要把数字字符转化为数值auto it = numstr.rbegin();while (it != numstr.rend()){//数字字符‘0’的ASCII码值为48num += (*it - '0') * quan;quan *= 10;it++;}st.push(num);numstr.clear();}//若遇到运算符把栈顶两个数据出栈,把栈顶数据当作右操作数,// 栈顶第二个数据当作左操作数,运算后把结果重新入栈else if (e == '+' || e == '-' || e == '*' || e == '/'){int b = st.top();st.pop();int a = st.top();st.pop();int c = 0;  //运算结果if (e == '+')c = a + b;else if(e == '-')c = a - b;else if (e == '*')c = a * b;elsec = a / b;st.push(c);}//遇到‘@’,退出范围forelse{break;}}//把栈里剩余的一个数据当作结果输出int ret = st.top();cout << ret;return 0;
}//思路2
using namespace std;
#include <iostream>
#include <stack>int main()
{stack<int> st;char e; //存放输入的字符int num = 0; //存放数字字符串转换后的数值while (cin >> e){if (e == '@')break;else if (e >= '0' && e <= '9'){//秦九韶算法num = num * 10 + (e - '0');}else if (e == '.'){st.push(num);num = 0; //num置0}else{int b = st.top(); //左操作数st.pop();int a = st.top(); //右操作数st.pop();int c = 0;  //运算结果if (e == '+')c = a + b;else if (e == '-')c = a - b;else if (e == '*')c = a * b;elsec = a / b;st.push(c);}}cout << st.top();return 0;
}

括号序列

题目描述

在这里插入图片描述

题目解析

解答本题要用到前面有效的括号题目的思路。
第一步和有效的括号类似,先遍历整个字符串,只不过这里会多一个步骤,需要标记当前字符是否匹配成功,所以需要一个bool数组st存放字符的标记值,数组st的下标和字符串str的下标一一对应,若某个字符匹配成功,就在st数组对应的下标位置置为true,因为数组st里的元素默认是false,如果匹配不成功则不做任何处理。
第二步再次遍历整个字符串,并创建一个新字符串ret用于存放配对完后的结果。遍历原字符串,若遇到字符的标记为true,直接插入ret,若不为true,则识别当前字符是那个具体括号,手动添加与之匹配的括号。
最后范围for输出字符串ret的结果就行了。

代码

using namespace std;
#include <iostream>
#include <stack>
#include <string>const int N = 110;
//用该数组下标标记字符串哪些位置的字符匹配成功
bool st[N]; //st数组定义在全局,值全被初始化为falseint main()
{string str;cin >> str;stack<int> stk; //栈存储字符串下标//遍历整个字符串for (int i = 0; i < str.size(); i++){char ch = str[i];//遇到左括号把左括号下标入栈if (ch == '(' || ch == '['){stk.push(i);}//遇到右括号与栈顶元素匹配//匹配成功的两个位置标记为trueelse{//若这时栈为空,无法匹配,让该位置保持falseif (stk.empty()){continue;}//top为栈顶字符元素下标int top = stk.top();//char为栈顶字符元素char left = str[top];//匹配成功if ((ch == ')' && left == '(') ||(ch == ']' && left == '[')){st[i] = st[top] = true;stk.pop();}//若未匹配成功,让st[i]、st[top]保持false}}//遍历字符串str,给未配对的括号配对string ret; //用于维护配对完后的字符串for (int j = 0; j < str.size(); j++){char ch = str[j];if (st[j] == true){//若该字符标记为true,直接插入retret += ch;}else{//若字符下标标记为false,需要手动为它匹配if (ch == '('){ret += ch;ret += ')';}else if (ch == ')'){ret += '(';ret += ch;}else if (ch == '['){ret += ch;ret += ']';}else if (ch == ']'){ret += '[';ret += ch;}}}for (auto e : ret){cout << e;}return 0;
}

这道题代码实现时要注意一个细节:

else
{if (stk.empty()){continue;}int top = stk.top();char left = str[top];else if ((ch == ')' && left == '(') ||(ch == ']' && left == '[')){st[i] = st[top] = true;}
}

这里else分支内部嵌套了一组if语句,其中else if应改为if,因为else if是else { if (…) { … }}的简写,必须有一个上层if作为前提,但是如果上层if内部用continue/break跳过了剩余逻辑,那么它的 “同级else if”会因缺少前提if而语法错误。
除此之外,这里不能用else if还有一个原因,else if的语法核心是:必须紧跟在一个if之后,中间不能有任何其他语句。否则会因无法匹配if而报错,而这段代码if和else if之间还有其他语句。

以上就是小编分享的全部内容了,如果觉得不错还请留下免费的关注和收藏
如果有建议欢迎通过评论区或私信留言,感谢您的大力支持。
一键三连好运连连哦~~

在这里插入图片描述

http://www.dtcms.com/a/361951.html

相关文章:

  • 腾讯位置商业授权微信小程序获取城市列表
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(二十三)控件中常用文本格式
  • 玩转OurBMC第二十一期:前端页面仪表盘的设计与使用实践
  • js 海康视频插件的具体步骤
  • QMainWindow使用QTabWidget添加多个QWidget
  • Simulink库文件-一种低通滤波模块搭建方法
  • 优化正则表达式性能:预编译与模式匹配的最佳实践
  • 均值滤波和中值滤波的简介、C语言实现和实测
  • 边缘计算设备 RK3576芯片
  • CGroup 资源控制组 + Docker 网络模式
  • NLP大语言模型数据准备
  • NLP技术突破:浅层与深层语义分析全解析
  • 嵌入式学习(day37) 数据库 Sqlite相关命令函数
  • Salesloft OAuth漏洞影响范围大幅增加,波及所有集成应用
  • 可编辑115页PPT | 某纸制品制造企业数字化转型战略规划项目建议书
  • 闭包的简单讲解
  • 三、数据结构
  • VMware安装
  • 基于docker-compose搭建EFK(Elasticsearch+fluentd+kibana)的日志平台
  • 【高等数学】第十章 重积分——第五节 含参变量的积分
  • python3中的除法/ (会把int变成float)向下取整//(不会改变int类型) 和 直接舍弃小数,向0截断
  • JVM性能监控工具的使用
  • python中的分代垃圾回收机制的原理【python进阶二、2】
  • 基于uni-app的校园综合服务平台开发实战
  • uni-app支持单多选、搜索、查询、限制能否点击组件
  • 掌握CRISPE框架:结构化提示词设计的终极指南
  • 【溜冰场轮滑计时计费扣次软件有哪些?】分享常见的几款软件,佳易王软件系列#软件功能解析操作教程
  • Tiny RDM:一个现代化轻量级的Redis桌面客户端
  • 盟接之桥说制造:浅谈本分和做正确的事情
  • 前端微前端架构深度实践:从单体应用到微前端的完整架构解决方案