3. <tag-栈和计算器总结>-lt.150. 逆波兰表达式求值 + lt.227. 基本计算器 || + lt.224. 基本计算器 dbc

重要: 栈与前中后缀表达式, 及波兰(给定前缀求值), 逆波兰(给定后缀求值)

  • 更详细的文章请看旧文: 点我

1. 波兰运算和逆波兰运算

注意: 其实无论是根据前缀表达式计算值, 还是根据后缀表达式计算值, 出栈和入栈规则都是完全一致的!
大体上的计算规则都是遇到数字就入栈, 遇到运算符就把数字连续出栈两次进行运算, 计算的结果继续入栈;
而前缀和后缀的差别在于对给定前后缀表达式遍历次序上的区别!

1.1 逆波兰表达式计算(给定后缀表达式求值)

在这里插入图片描述

1.2 波兰表达式(给定前缀表达式求值)

在这里插入图片描述

1. 给定了中缀, 如何用栈求出后缀呢?

中缀 -> 后缀

栈用来存储运算符和左括号;

在这里插入图片描述

2. 给定了中缀, 如何借助栈求出前缀呢?

lt.150. 逆波兰表达式求值

[案例需求]

在这里插入图片描述

[思路分析一, 借助系统栈]

  • 逆波兰表达式(后缀表达式)严格遵循「从左到右」的运算。
  • 计算逆波兰表达式的值时,使用一个栈存储操作数,从左到右遍历逆波兰表达式,进行如下操作:
    1. 正序遍历
    2. 栈存储数字, 遇到运算符出栈两次进行计算, 计算结果入栈如果遇到操作数,则将操作数入栈;
    • 其中先出栈的是右操作数,后出栈的是左操作数,使用运算符对两个操作数进行运算,将运算得到的新操作数入栈。
  1. 遍历完成, 栈中元素为最终结果

[代码实现]

class Solution {
    public int evalRPN(String[] tokens) {
        //逆波兰表达式
        /**
            数字栈, 后缀表达式正序遍历. 前缀表达式倒序遍历变为逆波兰
         */
        
        Stack<Integer> st = new Stack<>();

        /**
            string => int   Integer.parseInt()
            int => string  String.valueOf(y)
        
         */

          //逆波兰  == 后缀表达式
        // 后缀表达式计算求值
        //1. 正序遍历
        //2. 栈存储数字, 遇到运算符出栈两次进行计算, 计算结果入栈
        //3. 遍历完成, 栈中元素为最终结果

        int len = tokens.length;

        for(int i = 0; i < len; i++){
            
            String str = tokens[i];

            if(isNumber(str)){
                st.push(Integer.parseInt(str));
            }else{
                int b = st.pop();
                int a = st.pop();

                st.push(operation(str, a ,b));
            }
        }

        return st.peek();
    }

    public static boolean isNumber(String str){
        return !(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/"));
    }

    public int operation(String str, int a, int b){
        if(str.equals("+")) return a + b;
        if(str.equals("-")) return a - b;
        if(str.equals("*")) return a * b;
        if(str.equals("/")) return a / b;
        return -1;
    }
}

[思路分析二, 数组模拟栈 dbc]

在这里插入图片描述

[代码实现]

class Solution {
    public int evalRPN(String[] tokens) {
        int n = tokens.length;
        int[] stack = new int[(n + 1) / 2];
        int index = -1;
        for (int i = 0; i < n; i++) {
            String token = tokens[i];
            switch (token) {
                case "+":
                    index--;
                    stack[index] += stack[index + 1];
                    break;
                case "-":
                    index--;
                    stack[index] -= stack[index + 1];
                    break;
                case "*":
                    index--;
                    stack[index] *= stack[index + 1];
                    break;
                case "/":
                    index--;
                    stack[index] /= stack[index + 1];
                    break;
                default:
                    index++;
                    stack[index] = Integer.parseInt(token);
            }
        }
        return stack[index];
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/solution/ni-bo-lan-biao-da-shi-qiu-zhi-by-leetcod-wue9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在这里插入图片描述

lt.227. 基本计算器 ||

[案例需求]

在这里插入图片描述

[思路分析一, 单栈解法]

在这里插入图片描述

[代码实现]

class Solution {
    public int calculate(String s) {
        Deque<Integer> stack = new LinkedList<Integer>();
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (Character.isDigit(s.charAt(i))) {
                num = num * 10 + s.charAt(i) - '0';
            }
            if (!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1) {
                switch (preSign) {
                    case '+':
                        stack.push(num);
                        break;
                    case '-':
                        stack.push(-num);
                        break;
                    case '*':
                        stack.push(stack.pop() * num);
                        break;
                    default:
                        stack.push(stack.pop() / num);
                }
                preSign = s.charAt(i);
                num = 0;
            }
        }
        int ans = 0;
        while (!stack.isEmpty()) {
            ans += stack.pop();
        }
        return ans;
    }
}

在这里插入图片描述

[思路分析二, 双栈解法]

[代码实现]


在这里插入图片描述

lt.224. 基本计算器

[案例需求]

在这里插入图片描述

[思路分析]

[代码实现]


计算器实现是真的很恶心啊, 有没有一种方法通杀?

  • 题解
  • 其实文章最开始贴的一个笔者的旧文就有这种写法, 大致思路就是把给定的前缀表达式转换为后缀表达式, 然后再进行计算, 计算过程就是把运算符存储在符号栈中, 另外遇到左括号 ( 直接压入符号栈, 遇到右括号 ) 不断的出符号栈, 并和数字栈中出栈的两个数进行计算;
  • 在往符号栈中添加运算符时, 我们还需要维护一个运算符的优先级;
posted @   青松城  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示