LCR 150 逆波兰表达式求值

题目

根据逆波兰表示法,求该后缀表达式的计算结果。
有效的算符包括 + 、 − 、 ∗ 、 / +、-、*、/ +/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 0 0 的情况。
示例 1:
输入: t o k e n s = [ " 2 " , " 1 " , " + " , " 3 " , " ∗ " ] tokens = ["2","1","+","3","*"] tokens=["2","1","+","3",""] 输出: 9 9 9 解释:该算式转化为常见的中缀算术表达式为: ( ( 2 + 1 ) ∗ 3 ) = 9 ((2 + 1) * 3) = 9 ((2+1)3)=9
示例 2:
输入: t o k e n s = [ " 4 " , " 13 " , " 5 " , " / " , " + " ] tokens = ["4","13","5","/","+"] tokens=["4","13","5","/","+"] 输出: 6 6 6 解释:该算式转化为常见的中缀算术表达式为: ( 4 + ( 13 / 5 ) ) = 6 (4 + (13 / 5)) = 6 (4+(13/5))=6
示例 3:
输入: t o k e n s = [ " 10 " , " 6 " , " 9 " , " 3 " , " + " , " − 11 " , " ∗ " , " / " , " ∗ " , " 17 " , " + " , " 5 " , " + " ] tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] tokens=["10","6","9","3","+","11","","/","","17","+","5","+"] 输出: 22 22 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 ((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 ((10(6/((9+3)11)))+17)+5=((10(6/(1211)))+17)+5=((10(6/132))+17)+5=((100)+17)+5=(0+17)+5=17+5=22

思路

  1. 使用栈对其进行储存

逆波兰表达式其实就是后缀表达式,而波兰表达式就是前缀表达式。

  • 中缀表达式 》》后缀表达式(手算)

例如中缀表达式 ( 2 + 1 ) ∗ 3 − 4 ∗ 6 (2 + 1)* 3 - 4 * 6 2+1346 ,我们按照左优先的原则,如果两个运算符同级,那么左侧的运算符进行优先运算
image.png
我们首先给每个运算符进行优先级编号,按照左优先原则我们得到上面的结果。同时从左向右依次读取,将运算的两数的中缀顺序改为后缀顺序。
image.png
最后我们可以得到上面的结果,按照左优先原则得到的结果的运算符也是按照从小到大顺序的。

  • 中缀表达式 》》后缀表达式(机算)

对于计算机来说,中缀表达式转换成为后缀表达式自有一套自己的方式,首先创建一个栈来存储运算符,然后从左向右一次读取。
操作数:对于操作数,我们不用进行操作,直接取出。
运算符:对于运算符,我们依次弹出栈中优先级高于或等于自己(左优先原则)的运算符,直到遇到 " ( " "(" "" 或者栈空为止,不包含 " ( " "(" ""
界限符:对于界限符来说,遇到 " ( " "( " ""直接存入栈中,遇到 " ) " ")" ""一次弹出栈中所有的运算符,直到遇到 " ( " "( " ""为止, 包含 " ( " "(" ""
image.png
如上图所示,我们在遇到 " ) " ")" ""运算符时,我们将其一次弹出,但是由于界限符在后缀表达式中不改变运算结果,因此不需要加上。
image.png
当我们压入 " − " " - " "" 时,由于栈中的 " ∗ " " * " "" 的优先级高于它,因此我们将其弹出。
image.png
在最后全部读取完成的时候,我们将栈中的操作符依次弹出,最后得到的结果与上面手算的相同。

  • 后缀表达式计算(手算)

后缀表达式计算的方式其实很简单,从左向右依次读取,遇到运算数就放入中缀表达式中,遇到操作符就将其前面的两个运算数进行计算。
image.png
当我们读取到 " + " " + " "+" 时,我们将前面的操作数进行运算,并且在之后的运算中视为一个数。
image.png
按照这样的方式继续从左向右读取。
image.png
最终我们得到转换成功的中缀表达式并可以进行计算。

  • 后缀表达式计算(机算)

我们可以按照上面计算的方式进行运算,不过需要创建一个栈用来对于运算数进行存储。
image.png
当我们读取到 " + " " + " "+" 时,我们可以将栈中存储的前两个数字弹出进行运算,然后将运算结果存入重新栈中。
image.png
最终我们得到上图所示的结果。

  • 前缀表达式

前缀表达式的所有转换和运算都与后缀相同,只不过是将从左向右换成了从右向左和右优先原则,存入时也是从右向左。
在计算优先级的时候需要知道,是在从左向右读的时候同时有右优先原则,而不是直接在中间选一个优先级最高的。
image.png
而不是直接选取中间括号的优先级最高image.png

  • 中缀表达式的计算

中缀表达式的计算需要两个栈的辅助,一个在中缀表达式转换成后缀表达式中用来存储运算符,另一个在转换完的后缀表达式的运算中用来存储操作数。

此时我们因该已经知道了这道题的计算方法了,维护一个栈用来存储运算数。
代码

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        int len = tokens.size();
        stack<int> expression;
        for(int i = 0; i < len; i++){
            if(tokens[i] == "+"){
                int first = expression.top();
                //pop函数是没有返回值的,要先使用top(),在使用pop()。
                expression.pop();
                int second = expression.top();
                expression.pop();
                expression.push(first + second);
                continue;
            }

            if(tokens[i] == "*"){
                int first = expression.top();
                expression.pop();
                int second = expression.top();
                expression.pop();
                expression.push(first * second);
                continue;
            }

            if(tokens[i] == "-"){
                int first = expression.top();
                expression.pop();
                int second = expression.top();
                expression.pop();
                expression.push(second - first);
                continue;
            }

            if(tokens[i] == "/"){
                int first = expression.top();
                expression.pop();
                int second = expression.top();
                expression.pop();
                expression.push(second / first);
                continue;
            }

            //字符串转换成为整数类型。还可以使用stringstream
            // stringstream ss;
            // ss << tokens[i];
            // int num;
            // ss >> num;
            int num = stoi(tokens[i]);
            expression.push(num);

        }
        int res = expression.top();
        return res;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值