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

【LeetCode】【逆波兰表达式求解】

150. 逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。

有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

注意 两个整数之间的除法只保留整数部分。

可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
 

提示:

1 <= tokens.length <= 104
tokens[i] 是一个算符("+"、"-"、"*" 或 "/"),或是在范围 [-200, 200] 内的一个整数
 

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

逆波兰表达式也就是后缀表达式。

我们一般写的a+b都是中缀表达式,也就是运算符在中间

而后缀表达式就是运算符在后面,也就是ab+

中缀表达式是不能进行运算的,因为优先级的问题,不能顺序进行运算,比方说1+2*3

后缀表达式的话就可以将1+2*3转换成1 2 3*+,因为它将运算符的优先级排出来了,所以可以让计算机直接顺序运算 

后缀如何运算?

操作数的顺序不变,运算符按照优先级排序。

比防说我们的后缀表达式1 2 3*+

首先我们将操作数入栈,然后操作数就取连续两个栈顶数据运算,结果入栈

我们先将上面的后缀表达式中的1和2入栈,发现后面没有操作数,而是数字3,于是就接着入栈,然后发现后面是*,也就是操作数,我们就将栈连续出栈两个元素,也就是2和3出栈,然后进行乘法操作,运算出来的结果6再次入栈。然后我们接着读取,遇到了操作符+,然后我们再从我们的栈顶出两个元素1和6,进行加法操作,获得的结果7再次入栈,然后我们发现我们的后缀表达式已经读取完毕了,然后我们的栈中就是我们的计算结果。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        //遍历tokens中的元素
        for(auto& str:tokens)
        {
            //如果是操作符就进行取操作数,然后进行运算的操作

            if(str=="+"||str=="-"||str=="*"||str=="/")
            {
                //注意,先取出来的是右操作数,然后取出来的是左操作数
                int right=st.top();
                st.pop();
                int left=st.top();
                st.pop();
            //switch-case中传入的不能是字符串string
                switch(str[0])
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;

                }
                
            }
            else
            {
                //如果是操作数的话就将其转换成数字然后入栈
                //stoi就是将字符串转换成int类型(string to int)
                st.push(stoi((str)));
            }
        }
        return st.top();
    }
private:
    //创建一个栈
    stack<int> st;
};

我们发现这样的话咱的int类型hold不住数据,在计算乘法的时候会崩掉的

所以哦我们将int全部都改成long long

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        //遍历tokens中的元素
        for(auto& str:tokens)
        {
            //如果是操作符就进行取操作数,然后进行运算的操作

            if(str=="+"||str=="-"||str=="*"||str=="/")
            {
                //注意,先取出来的是右操作数,然后取出来的是左操作数
                long long right=st.top();
                st.pop();
                long long left=st.top();
                st.pop();
            //switch-case中传入的不能是字符串string
                switch(str[0])
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;

                }
                
            }
            else
            {
                //如果是操作数的话就将其转换成数字然后入栈
                //stoll就是将字符串转换成longlong类型(string to long long)
                st.push(stoll((str)));
            }
        }
        return st.top();
    }
private:
    //创建一个栈
    stack<long long> st;
};

中缀表达式如何转换成后缀表达式?

中缀表达式:1+2*3

后缀表达式:1 2 3 * +

中缀转后缀就是要调节运算符的优先级

1.操作数输出

2.如果当前栈为空的操作符比操作符栈的栈顶的操作符的优先级更高,就入栈,

否则就说明新的操作符比操作符栈栈顶的优先级低或相等,也就是说明当前栈顶的操作符对应的运算可以执行

上面的12入数据栈,+入操作符栈,然后遇到*号,优先级比+高,就继续将3入数据栈,*入操作符栈。然后发现读取完毕了,就将23*取出,先进行运算,然后再将23*作为一整个结果压入数据栈,然后再取出1和+,和23*结合形成123*+,也就形成了后缀表达式

再举一个例子1+2*3/4+5-6

1和2如操作数栈,+如操作符栈,然后读取到*,优先级比+高,就如操作符栈,3也同时进入操作数栈,/和*的优先级相同,就说明2*3可以运行,就取出23*压入操作数栈,然后将4和/分别压入操作数栈和操作符栈,然后继续读取,发现+比/的优先级第,所以前面的/可以运行,就取出23*和4与操作符/构成23*4/,重新将这个结果压入操作数栈,然后向后读取的4与5之间的+与1+2之间的+优先级相同,就说明前面的1与2之间的+可以运算,然后就可以将1和23*4/进行加法运算,形成123*4/+然后5后面的-与45之间的+优先级相投,按照上面的操作形成123*4/+5+,然后后面的6也是以此类推,形成123*4/+56-

如果遇到括号怎么办?

1+(2+3)*4-5

1,+入操作数栈和操作符栈,然后遇到(的话,可以设置一个flag=true来表示遇到括号了。我们括号的优先级是最高的。也就是先将23+如操作数栈,然后遇到*号,优先级比+更高,所以形成23+4*压入操作数栈,后面的-与前面1后面的+的优先级相同,于是前面的+运算可以执行,也就是将123+4*+,然后再计算-5,也就是123+4*+5-,得到最终结果。

相关文章:

  • C++类和对象(中—1) —— 构造函数、析构函数、拷贝构造函数
  • SsmAjaxJson分页效果的操作(第十七课)
  • sklearn机器学习——day19
  • GrapeCity Documents for PDF (GcPDF)
  • el与data的两种写法
  • 超常用的网络工具命令汇总
  • java-php-python-springboo动物在线领养网站计算机毕业设计
  • JavaScript try-catch 处理错误和异常指南
  • Python文件的读写及常用文件的打开方式
  • MyBatis 中 #{} 和 ${} 的区别看完这篇文章一目了然
  • 实时即未来,车联网项目之原始终端数据实时ETL【二】
  • python 的re.findall的Bug以及解决方法
  • 在Windows系统上部署DHCP服务器
  • Java多线程~CAS的原理及其应用
  • [CSS]盒子模型
  • 《Java编程思想》读书笔记-对象导论
  • C++类中的特殊成员函数
  • canvas绘制圆角头像
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • ECMAScript6(0):ES6简明参考手册
  • ES6之路之模块详解
  • input的行数自动增减
  • interface和setter,getter
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • JavaScript 一些 DOM 的知识点
  • Lucene解析 - 基本概念
  • Mysql数据库的条件查询语句
  • RxJS: 简单入门
  • webpack入门学习手记(二)
  • windows-nginx-https-本地配置
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 设计模式走一遍---观察者模式
  • 协程
  • 1.Ext JS 建立web开发工程
  • MPAndroidChart 教程:Y轴 YAxis
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • #pragma once与条件编译
  • $.ajax中的eval及dataType
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (分布式缓存)Redis分片集群
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .net core 控制台应用程序读取配置文件app.config
  • .net wcf memory gates checking failed
  • .NetCore项目nginx发布
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • ?php echo ?,?php echo Hello world!;?
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @RequestBody详解:用于获取请求体中的Json格式参数
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)