diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 78dfae3e..176ea687 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -51,7 +51,7 @@ ``` -逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。 +逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。 @@ -61,11 +61,11 @@ * 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。 -* 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。 +* 适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。 # 思路 -《代码随想录》算法视频公开课:[栈的最后表演! | LeetCode:150. 逆波兰表达式求值](https://www.bilibili.com/video/BV1kd4y1o7on),相信结合视频在看本篇题解,更有助于大家对本题的理解。 +《代码随想录》算法视频公开课:[栈的最后表演! | LeetCode:150. 逆波兰表达式求值](https://www.bilibili.com/video/BV1kd4y1o7on),相信结合视频再看本篇题解,更有助于大家对本题的理解。 在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。 @@ -73,7 +73,7 @@ 那么来看一下本题,**其实逆波兰表达式相当于是二叉树中的后序遍历**。 大家可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。 -但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。 +但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后序遍历的方式把二叉树序列化了,就可以了。 在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** @@ -118,9 +118,9 @@ public: 我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。 -例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算法,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦! +例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算符,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦! -那么将中缀表达式,转化为后缀表达式之后:["4", "13", "5", "/", "+"] ,就不一样了,计算机可以利用栈里顺序处理,不需要考虑优先级了。也不用回退了, **所以后缀表达式对计算机来说是非常友好的。** +那么将中缀表达式,转化为后缀表达式之后:["4", "13", "5", "/", "+"] ,就不一样了,计算机可以利用栈来顺序处理,不需要考虑优先级了。也不用回退了, **所以后缀表达式对计算机来说是非常友好的。** 可以说本题不仅仅是一道好题,也展现出计算机的思考方式。 @@ -161,6 +161,24 @@ class Solution { } ``` +python3 + +```python +class Solution: + def evalRPN(self, tokens: List[str]) -> int: + stack = [] + for item in tokens: + if item not in {"+", "-", "*", "/"}: + stack.append(item) + else: + first_num, second_num = stack.pop(), stack.pop() + stack.append( + int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面 + ) + return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的 + +``` + Go: ```Go func evalRPN(tokens []string) int { @@ -169,7 +187,7 @@ func evalRPN(tokens []string) int { val, err := strconv.Atoi(token) if err == nil { stack = append(stack, val) - } else { + } else { // 如果err不为nil说明不是数字 num1, num2 := stack[len(stack)-2], stack[(len(stack))-1] stack = stack[:len(stack)-2] switch token { @@ -191,27 +209,31 @@ func evalRPN(tokens []string) int { javaScript: ```js - -/** - * @param {string[]} tokens - * @return {number} - */ -var evalRPN = function(tokens) { - const s = new Map([ - ["+", (a, b) => a * 1 + b * 1], - ["-", (a, b) => b - a], - ["*", (a, b) => b * a], - ["/", (a, b) => (b / a) | 0] - ]); +var evalRPN = function (tokens) { const stack = []; - for (const i of tokens) { - if(!s.has(i)) { - stack.push(i); - continue; + for (const token of tokens) { + if (isNaN(Number(token))) { // 非数字 + const n2 = stack.pop(); // 出栈两个数字 + const n1 = stack.pop(); + switch (token) { // 判断运算符类型,算出新数入栈 + case "+": + stack.push(n1 + n2); + break; + case "-": + stack.push(n1 - n2); + break; + case "*": + stack.push(n1 * n2); + break; + case "/": + stack.push(n1 / n2 | 0); + break; + } + } else { // 数字 + stack.push(Number(token)); } - stack.push(s.get(i)(stack.pop(),stack.pop())) } - return stack.pop(); + return stack[0]; // 因没有遇到运算符而待在栈中的结果 }; ``` @@ -280,24 +302,6 @@ function evalRPN(tokens: string[]): number { }; ``` -python3 - -```python -class Solution: - def evalRPN(self, tokens: List[str]) -> int: - stack = [] - for item in tokens: - if item not in {"+", "-", "*", "/"}: - stack.append(item) - else: - first_num, second_num = stack.pop(), stack.pop() - stack.append( - int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面 - ) - return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的 - -``` - Swift: ```Swift func evalRPN(_ tokens: [String]) -> Int {