• 栈与队列5:逆波兰表达式求值


    主要是我自己刷题的一些记录过程。如果有错可以指出哦,大家一起进步。
    转载代码随想录
    原文链接:
    代码随想录
    leetcode链接:150. 逆波兰表达式求值

    题目:

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

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

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

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

    示例:

    示例 1:

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

    示例 2:

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

    示例 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    提示:

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

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

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

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

    思路:

    在上一篇文章中1047.删除字符串中的所有相邻重复项提到了 递归就是用栈来实现的。

    所以栈与递归之间在某种程度上是可以转换的! 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。

    那么来看一下本题,其实逆波兰表达式相当于是二叉树中的后序遍历。 大家可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。

    但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。

    在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么这岂不就是一个相邻字符串消除的过程,和1047.删除字符串中的所有相邻重复项 (opens new window)中的对对碰游戏是不是就非常像了。
    如动画所示:
    请添加图片描述
    相信看完动画大家应该知道,这和1047. 删除字符串中的所有相邻重复项 (opens new window)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
    C++代码如下:

    class Solution {
    public:
        int evalRPN(vector<string>& tokens) {
            // 力扣修改了后台测试数据,需要用longlong
            stack<long long> st; 
            for (int i = 0; i < tokens.size(); i++) {
                if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                    long long num1 = st.top();
                    st.pop();
                    long long 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(stoll(tokens[i]));
                }
            }
    
            int result = st.top();
            st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    题外话

    我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。

    例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算法,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦!

    那么将中缀表达式,转化为后缀表达式之后:[“4”, “13”, “5”, “/”, “+”] ,就不一样了,计算机可以利用栈里顺序处理,不需要考虑优先级了。也不用回退了, 所以后缀表达式对计算机来说是非常友好的。

    可以说本题不仅仅是一道好题,也展现出计算机的思考方式。

    在1970年代和1980年代,惠普在其所有台式和手持式计算器中都使用了RPN(后缀表达式),直到2020年代仍在某些模型中使用了RPN。

    自己的代码

    #define LL long long 
    class Solution {
    public:
    	int evalRPN(vector<string>& tokens) {
    		for (const string& ch : tokens) {
    			//符号就取出两个栈中元素做运算在加入栈中
    			if (ch == "+" || ch == "-" || ch == "*" || ch == "/") {
    				LL b = result.top();//算数符号右边
    				result.pop();
    				LL a = result.top();//算数符号左边
    				result.pop();
    				if (ch == "+") {
    					result.push(a + b);
    				}
    				else if (ch == "-") {
    					result.push(a - b);
    				}
    				else if (ch == "*") {
    					result.push(a * b);
    				}
    				else if (ch == "/") {
    					result.push(a / b);
    				}
    			}
    			else {//数字就转化一下压入栈中
    				result.push(stoll(ch));
    			}
    		}
    		return result.top();
    	}
    private:
    	stack<LL>result;
    	/*int str2int(const string& str) {
    		int num = 0;
    		if (str[0] == '-') {
    			for (int i = 1; i < str.size(); ++i) {
    				num = num*10 + str[i] - '0';
    			}
    			return -num;
    		}
    		else {
    			for (int i = 0; i < str.size(); ++i) {
    				num = num * 10 + str[i] - '0';
    			}
    			return num;
    		}
    	}*/
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
  • 相关阅读:
    Spring AOP
    用Python实现数据透视表、音频文件格式转换
    LaTeX中的数学符号
    力扣每日一题74:搜索二维矩阵
    h5钉钉导航栏实时更新(跟踪标题)标题
    解决passwd:Authentication token manipulation error
    ESMAScript(1)
    生命 周期
    Oracle——用户、角色、权限的创建、删除、修改
    江西股权转让项目:萍乡市天子山铁矿有限公司32%股权转让
  • 原文地址:https://blog.csdn.net/Ge_yangwen/article/details/128204466