C++题解 | 逆波兰表达式相关

news/2024/5/9 13:01:38/文章来源:https://blog.csdn.net/weixin_61437787/article/details/130390631

✨个人主页: 夜 默
🎉所属专栏: C/C++相关题解
🎊每篇一句: 图片来源

  • A year from now you may wish you had started today.
    • 明年今日,你会希望此时此刻的自己已经开始行动了。

屹立不倒


文章目录

  • 🌇前言
  • 🏙️正文
    • 1、什么是逆波兰表达式?
    • 2、150. 逆波兰表达式求值 ⭐⭐
    • 3、224. 基本计算器 ⭐⭐⭐
  • 🌆总结


🌇前言

好久没有更新题解系列博客了,今天要学习的是 逆波兰表达式,作为计算机中的重要概念,值得花时间去学习,并且其中还必须使用 容器适配器,非常适合用来练手

逆波兰表达式


🏙️正文

1、什么是逆波兰表达式?

逆波兰表达式 又称为 后缀表达式,我们从小到大学习的数学相关运算式都是 前缀表达式

  • 前缀表达式:运算符在操作数中间 (a + b) * c
  • 后缀表达式:运算符在操作数后面 a b + c *

为什么会存在这种反人类的表达式呢?

  • 因为运算式中,可能存在 ( ) 提高运算优先级的现象,计算机不像人类一样,可以一眼找到 ( ) 进行运算,只能通过特殊方法,处理运算式,使其能进行正常运算

因此,后缀表达式中是没有括号的

操作数:a、b、c
运算符:+、*

后缀表达式 的计算步骤:

  1. 从左往右,扫描表达式
  2. 获取 操作数1操作数2
  3. 再获取 运算符
  4. 进行运算:操作数1 运算符 操作数2,获取运算结果
  5. 将运算结果继续与后续 操作数运算符 进行计算

比如计算 12+3*

  • 首先计算 1 + 2 = 3
  • 其次再计算 3 * 3 = 9

最后的 9 就是最终运算结果,逆波兰表达式(后缀表达式)有效解决了计算时的优先级问题

了解 逆波兰表达式 基础知识后,就可以尝试解决相关问题了~


2、150. 逆波兰表达式求值 ⭐⭐

首先来看看第一题,也是比较简单的一题:150.逆波兰表达式求值

题目链接:150.逆波兰表达式求值

题目

题目要求:根据 逆波兰表达式 计算出结果

这里可以直接根据 逆波兰表达式(后缀表达式) 的计算步骤进行解题

解题思路:

  1. 从左往右扫描表达式(遍历即可)
  2. 遇到操作数(数字),入栈
  3. 遇到运算符,取出栈中的两个两个操作数,进行计算
  4. 将计算结果重新入栈
  5. 如此重复,直到表达式被扫描完毕

所需要的辅助工具:stack
复杂度分析:

  • 时间复杂度 O(N) 遍历一遍表达式 + 出栈入栈
  • 空间复杂度 O(N) 需要使用大小足够的栈

图解

转化为代码是这样的:

class Solution {
public:int evalRPN(vector<string>& tokens) {//首先需要一个栈,用来存储操作数stack<int> numStack;//对表达式进行遍历for (size_t pos = 0; pos != tokens.size(); pos++){//判断是否为操作数//需要注意负数,负数大小是大于1的if (isdigit(tokens[pos][0]) || tokens[pos].size() > 1){//满足条件,入栈//注意:入栈的是整型!numStack.push(stoi(tokens[pos]));}else{//此时为运算符,需要进行运算//注意:先取的是右操作数int rightNum = numStack.top();numStack.pop();int leftNum = numStack.top();numStack.pop();char oper = tokens[pos][0];   //运算符int val = 0;    //运算结果switch (oper){case '+':val = leftNum + rightNum;break;case '-':val = leftNum - rightNum;break;case '*':val = leftNum * rightNum;break;case '/':val = leftNum / rightNum;break;default:break;}//将运算结果入栈numStack.push(val);}}//此时栈中的元素,就是计算结果return numStack.top();}
};

运行结果:
结果

需要注意的点:

  • isdigit 函数可以判断字符是否数字字符
  • 判断是否为操作数时,需要注意负数的情况,如 -100,可以通过判断字符串大小解决(运算符大小只为1)
  • 操作数入栈时,入的是整型,而非字符串,可以使用 stoi 函数进行转换
  • 取操作数时,先取到的是右操作数,-/ 这两个运算符需要注意运算顺序
  • 获得运算结果后,需要再次入栈

3、224. 基本计算器 ⭐⭐⭐

直接利用 后缀表达式 计算出结果很简单,但将 中缀表达式 转为 后缀表达式 就比较麻烦了

在力扣中就存在这样一道 困难题

题目链接:基本计算器

题目
题目要求:根据 中缀表达式,计算出结果

注意: 给出的 中缀表达式 中只涉及 +- 运算,但是其中又会存在很多特殊情况

特殊情况
为了使得这些特殊情况统一化,在进行表达式转换前,需要先去除其中的空格,这样就能以较为统一的视角解决问题

解题思路:

  1. 去除 中缀表达式 中的空格,方便后续进行转换
  2. 获取 逆波兰表达式(后缀表达式) (重难点)
  3. 根据 逆波兰表达式 求出结果即可

如何将 中缀表达式 转换为 后缀表达式 ?

  1. 操作数输出(非打印,而是尾插至 vector 中)
  2. 运算符:如果栈为空,直接入栈;如果栈不为空,与栈顶运算符进行优先级比较,如果比栈顶运算符优先级高,入栈,否则将栈顶运算符弹出(输出),继续比较
  3. 对于 (),认为它们的优先级都为最低,并且 ( 直接入栈,而 ) 直接弹出栈顶元素,直到遇见 (
  4. 最后将栈中的运算符全部弹出

思维导图

注意: 对于可能存在的负数,需要进行特别处理

  • - 单独出现时(左右都没有操作数),表示此时需要将右边括号中的计算结果 * -1,此时可以直接先输出元素 0,后续进行 0 - val 时,可以满足需求
  • - 仅有右边有操作数时,此时为一个单独出现的负数,输出此负数即可
  • - 左右都有操作数时,此时的 - 就是一个单纯的运算符
class Solution {
public://去除空格int spaceRemove(string& s){int begin = 0;int end = 0;int alphaNum = 0;while (end != s.size()){if (s[end] != ' '){if (s[end] != '(' && s[end] != ')')alphaNum++;s[begin] = s[end];begin++;end++;}elseend++;}s.resize(begin);return alphaNum;}//判断是否为负数bool isNega(const string& s, int i){//合法的负数:左边为 '(' 或者 左边为空return s[i] == '-' && (i == 0 || s[i - 1] == '(');}//获取逆波兰表达式void getAntiPoland(vector<string>& tokens, string s){//借助栈,存储运算符stack<char> oper;size_t i = 0;while (i < s.size()){string str;//操作数直接输出if (isdigit(s[i]) || isNega(s, i)){//有可能为负数if (s[i] == '-'){//特殊情况,'-' 单独出现,不配合数字if (i + 1 < s.size() && !isdigit(s[i + 1])){str += '0';oper.push(s[i++]);}//普通负数的情况else{str += s[i];i++;}}//处理多位数的情况while (isdigit(s[i])){str += s[i];i++;}}else{//此时为运算符//栈空 或者 '(' 直接入栈if (oper.empty() || s[i] == '(')oper.push(s[i]);else{if (s[i] == ')'){//此时需要不断弹出char tmp = oper.top();oper.pop();while (tmp != '('){str += tmp;tmp = oper.top();oper.pop();}}else if (oper.top() != '('){//此时弹出并入栈str = oper.top();oper.pop();oper.push(s[i]);}else{//此时该运算符的优先级比前面的高,直接入栈oper.push(s[i]);}}i++;}if (!str.empty())tokens.push_back(str);  //计入中缀表达式}//最后需要将栈中的运算符全部弹出string str;while (!oper.empty()){str += oper.top();oper.pop();}if (!str.empty())tokens.push_back(str);}int evalRPN(vector<string>& tokens) {//首先需要一个栈,用来存储操作数stack<int> numStack;//对表达式进行遍历for (size_t pos = 0; pos != tokens.size(); pos++){//判断是否为操作数//需要注意负数,负数大小是大于1的if (isdigit(tokens[pos][0]) || tokens[pos].size() > 1){//满足条件,入栈//注意:入栈的是整型!numStack.push(stoi(tokens[pos]));}else{//此时为运算符,需要进行运算//注意:先取的是右操作数int rightNum = numStack.top();numStack.pop();int leftNum = numStack.top();numStack.pop();char oper = tokens[pos][0];   //运算符int val = 0;    //运算结果switch (oper){case '+':val = leftNum + rightNum;break;case '-':val = leftNum - rightNum;break;default:break;}//将运算结果入栈numStack.push(val);}}//此时栈中的元素,就是计算结果return numStack.top();}int calculate(string s) {//核心:运算符入栈,操作数输出,根据运算符优先级进行弹出int alphaNum = spaceRemove(s); //为了方便后续操作,可以先去除空格vector<string> tokens;  //存储操作数+运算符的后缀表达式tokens.reserve(alphaNum);	//提前扩容,避免造成浪费getAntiPoland(tokens, s);   //获取逆波兰表达式(后缀表达式)int val = evalRPN(tokens);  //复用之前写的代码return val;}
};

结果

注:因为走的是先转换,再计算的步骤,所以整体性能会比较差,但其中加入了 逆波兰表达式 的相关知识,还是比较适合用来练手的


🌆总结

以上就是本次 逆波兰表达式 相关内容了,希望你在看完本文后能够有所收获

如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!

如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正


星辰大海

相关文章推荐

C语言题解 | 去重数组&&合并数组

C语言题解 | 消失的数字&轮转数组

C语言题解——除自身以外数组的乘积(力扣 第238题)

剑指Offer 第53题:数字在升序数组中出现的次数

C语言题解——倒置字符串(剑指Offer 第58题)

感谢支持

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java获取类结构信息

package com.hspedu.reflection;import org.junit.jupiter.api.Test;import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;/*** author 韩顺平* version 1.0* 演示如何通过反射获…

ROC的理解

ROC 的由来 ROC 曲线是由混淆矩阵衍生来的指标。 混淆矩阵如图所示&#xff0c; 二ROC曲线的横坐标为 FPR&#xff0c;纵坐标为 TPR&#xff0c;计算公式分别是 F P R F P F P T N , 也就是 F P R F P F A L S E FPR \frac{FP}{FPTN}, 也就是 FPR \frac{FP}{FALSE} FP…

一条命令搭建HTTP服务器

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章&#xff1a;【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…

TCP流量控制与拥塞控制

什么是流量控制 一条TCP连接的每一侧主机都为该连接设置了接收缓存。当该TCP连接接收到正确的、有序的报文段&#xff0c;就会将数据放入接收缓存。相关联的应用会从缓存中读取数据。 如果发送者发送数据过快、过多&#xff0c;而接收方的应用程序从缓冲区读取的速度较慢&…

面试题30天打卡-day13

1、Linux 中的硬链接和软连接是什么&#xff0c;二者有什么区别&#xff1f; 在Linux系统下&#xff0c;有两种链接文件&#xff0c;一种是硬链接&#xff08;Hard Link&#xff09;&#xff0c;一种是软链接&#xff0c;也称为符号链接&#xff08;Symbolic Link&#xff09;…

Codeforces Round 867 (Div. 3)

Problem - E - Codeforces 思路&#xff1a; 首先&#xff0c;如果n为奇数&#xff0c;中间那个数无法调整&#xff0c;所以只考虑偶数只有26个字母&#xff0c;我们用cnt[]记录每个字母需要交换的对数。设maxn为交换对数最多的字母。显然&#xff0c;如果cnt[maxn]>n/2,显…

006-reg

程序 程序输入用户名和序列号&#xff0c;会被存放在reg.dll里&#xff0c;程序重启验证 查壳 无壳&#xff0c;Delphi程序 载入OD分析 搜索到可疑字符串 看未注册附近 在这个地方传入的Username和SN&#xff0c;进call 验证了SN的长度和字符类型 在这个CALL里计算…

智加科技+舍弗勒,首发量产正向开发的智能重卡冗余转向

对于自动驾驶赛道来说&#xff0c;感知、规划和控制&#xff0c;除了计算平台、算法等核心上层软硬件支持&#xff0c;底盘控制系统同样是关键一环。事实上&#xff0c;从Demo到规模化量产&#xff0c;更好的车身控制能力以及冗余备份&#xff0c;也是自动驾驶公司迈入2.0阶段的…

Mybatis 全局配置文件 mybatis-config.xml

1、全局配置文件的用处 mybatis通过配置文件可以配置数据源、事务管理器、运行时行为、处理别名、类型处理、插件等信息。在mybatis应用初始化时&#xff0c;程序会解析全局配置文件&#xff0c;使用配置的信息实例化Configuration组件&#xff0c;完成基本配置的初始化。在my…

【Linux】解决切换用户出现bash-4.2$问题创建普通用户并设置密码、授权

【问题描述】 linux中创建了一个wxh用户&#xff0c;然后使用su命令切换用户后&#xff0c;终端提示符显示成“bash-4.2$”而不是[rootlocalhost wxh]#&#xff0c;导致ll等命令无法执行。 [rootlocalhost xhh]# su wxh bash-4.2$ ll bash: ll: 未找到命令 【原因】 没有在hom…

找出1-1000中的所有完美数

再次练习查找完美数&#xff0c;找出 1-1000 中的所有完美数。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… 地址&#xff1a;https://l…

JVM 调优

大部分的情况都是由于企业内部代码逻辑不合理导致。 JVM内部性能优化 栈上分配方法内联JVM的自适应调整 JVM改错 大并发内存不足OOM 内存泄漏GC频繁CPU飙升 JVM的调优的原则是让你各项指标尽可能的利用到你硬件的性能瓶颈。 JVM的性能优化可以分为代码层面和非代码层面。 …

PyTorch实战3:天气识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营-第P3周&#xff1a;天气识别&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 目录 一、前期准备1、导入数据2、transforms.Compose详…

【Python入门第五十四天】Python丨NumPy ufuncs

什么是 ufuncs&#xff1f; ufuncs 指的是“通用函数”&#xff08;Universal Functions&#xff09;&#xff0c;它们是对 ndarray 对象进行操作的 NumPy 函数。 为什么要使用 ufuncs&#xff1f; ufunc 用于在 NumPy 中实现矢量化&#xff0c;这比迭代元素要快得多。 它们…

线程的生命周期以及sleep()方法和wait()方法

三种休眠状态&#xff1a;Blocked&#xff0c;Waiting&#xff0c;Timed_Waiting 注意两个Blocked态是不一样的&#xff0c;上面的Blocked只要睡眠时间到了马上进入运行态&#xff0c;下面处于Blocked的线程还需要抢到锁才能进入运行态 sleep()和wait()方法&#xff1a; sleep…

【hello Linux】进程间通信——匿名管道

目录 前言&#xff1a; 总结下上述的内容&#xff1a; 1. 进程间通信目的 2. 进程间通信的分类 1. 匿名管道 2. 匿名管道的使用 1. 匿名管道的创建 2. 使用匿名管道进行父子间通信 Linux&#x1f337; 前言&#xff1a; 进程具有独立性&#xff0c;拥有独立的数据、代码及其他…

论文阅读:PVO: Panoptic Visual Odometry

全景视觉里程计、同时做全景分割和视觉里程计 连接&#xff1a;PVO: Panoptic Visual Odometry 0.Abstract 我们提出了一种新的全景视觉里程计框架PVO&#xff0c;以实现对场景运动、几何和全景分割信息的更全面的建模。我们将视觉里程计(VO)和视频全景分割(VPS)在一个统一的…

STM32F4_SRAM中调试代码

目录 1. 在RAM中调试代码 2. STM32的三种存储方式 3. STM32的启动方式 4. 实验过程 通过上一节的学习&#xff0c;我们已经了解了SRAM静态存储器&#xff1b; 1. 在RAM中调试代码 一般情况下&#xff0c;我们在MDK中编写工程应用后&#xff0c;调试时都是把程序下载到芯片…

Java_异常

Java_异常 1.什么是异常 ​ 生活中的异常&#xff1a;感冒发烧、电脑蓝屏、手机死机等。 ​ 程序中的异常&#xff1a;磁盘空间不足、网络连接中断、被加载的资源不存在等。 ​ 程序异常解决办法&#xff1a;针对程序中非正常情况&#xff0c;Java语言引入了异常&#xff0…

注意力机制:基于Yolov5/Yolov7的Triplet注意力模块,即插即用,效果优于cbam、se,涨点明显

论文&#xff1a;https://arxiv.org/pdf/2010.03045.pdf 本文提出了可以有效解决跨维度交互的triplet attention。相较于以往的注意力方法&#xff0c;主要有两个优点&#xff1a; 1.可以忽略的计算开销 2.强调了多维交互而不降低维度的重要性&#xff0c;因此消除了通道和权…