栈与队列:有没有想过计算机是如何处理表达式的?
本文:https://github.com/youngyangyang04/leetcode-master已经收录,里面还有leetcode刷题攻略、各个类型经典题目刷题顺序、思维导图,可以fork到自己仓库,有空看一看一定会有所收获,如果对你有帮助也给一个star支持一下吧!
150. 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1: 输入: ["2", "1", "+", "3", " * "] 输出: 9 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2: 输入: ["4", "13", "5", "/", "+"] 输出: 6 解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3: 输入: ["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 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
- 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
思路
在上一篇文章中栈与队列:匹配问题都是栈的强项提到了 递归就是用栈来实现的。
所以「栈与递归之间在某种程度上是可以转换的」,这一点我们在后续讲解二叉树的时候,会更详细的讲解到。
那么来看一下本题,「其实逆波兰表达式相当于是二叉树中的后序遍历」。大家可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。
但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么「这岂不就是一个相邻字符串消除的过程,和栈与队列:匹配问题都是栈的强项中的对对碰游戏是不是就非常像了。」
如动画所示:
相信看完动画大家应该知道,这和1047. 删除字符串中的所有相邻重复项是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
代码如下:
C++代码
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for (int i = 0; i < tokens.size(); i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
int num1 = st.top();
st.pop();
int num2 = st.top();
st.pop();
if (tokens[i] == "+") st.push(num2 + num1);
if (tokens[i] == "-") st.push(num2 - num1);
if (tokens[i] == "*") st.push(num2 * num1);
if (tokens[i] == "/") st.push(num2 / num1);
} else {
st.push(stoi(tokens[i]));
}
}
int result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}
};
题外话
我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。
例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算法,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦!
那么将中缀表达式,转化为后缀表达式之后:["4", "13", "5", "/", "+"] ,就不一样了,计算机可以利用栈里顺序处理,不需要考虑优先级了。也不用回退了, 「所以后缀表达式对计算机来说是非常友好的。」
可以说本题不仅仅是一道好题,也展现出计算机的思考方式。
在1970年代和1980年代,惠普在其所有台式和手持式计算器中都使用了RPN(后缀表达式),直到2020年代仍在某些模型中使用了RPN。
参考维基百科如下:
During the 1970s and 1980s, Hewlett-Packard used RPN in all of their desktop and hand-held calculators, and continued to use it in some models into the 2020s.
在留言区留下你的思路吧!
-------end-------
我是程序员Carl,哈工大师兄,先后在腾讯和百度从事技术研发多年,利用工作之余重刷leetcode。
我的B站(里面有我讲解的算法视频以及编程相关知识):https://space.bilibili.com/525438321
我的github:https://github.com/youngyangyang04
更多 精彩算法文章尽在:代码随想录,关注后,回复「Java」「C++」「python」「简历模板」等等,有我整理多年的学习资料,可以加我 微信,备注「个人简介」+「组队刷题」,拉你进入刷题群(无任何广告,纯个人分享),每天一道经典题目分析,我选的每一道题目都不是孤立的,而是由浅入深一脉相承的,如果跟住节奏每篇连续着看,定会融会贯通。
- VR技术的进步推动工业机器人革命
- tLinux 2.2下安装Mono 4.8
- WordPress评论回复邮件样式美化教程
- 基于Aspose.Pdf把pdf文件每一页转换为图片
- 分布式文件存储的数据库开源项目MongoDB
- 使用 JavaScriptService 在.NET Core 里实现DES加密算法
- 拒绝全英文垃圾评论!仅用代码实现
- 在.NET Core 里使用 BouncyCastle 的DES加密算法
- 微信小程序:为了满足三方需求,我们一直在改变
- 让陌生人能够相互自由交易和支付
- 斯坦福发布首份 AI Index 报告,AI 研究者不再茫然
- jQuery仿极客公园火箭发射“返回顶部”效果(初始篇)
- Java程序员必读,Java设计模式应该遵循哪些原则
- Visual Studio 2010快速参考指南里头的Scrum海报
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- NLP简报(Issue#9)
- 这些pandas技巧你还不会吗 | Pandas实用手册(PART II)
- 芝麻街跨界NLP,没有一个ERNIE是无辜的
- python实现多层感知机
- 数据分析必备!Pandas实用手册(PART III)
- python实现决策树
- NLP简报(Issue#10)
- Transformer温故知新
- 【作者解读】ERNIE-GEN : 原来你是这样的生成预训练框架!
- Python中那些低调有趣的模块
- 01背包问题讲解(动态规划)
- python实现随机森林
- 在mysql中order by是怎样工作的?
- 多线程应用 - 阻塞队列ArrayBlockingQueue详解
- Java虚拟机 - 超级详细的类加载说明