Leetcode面试经典150题-150.逆波兰表达式求解

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

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

示例 2:

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

示例 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 <= tokens.length <= 104
  • tokens[i] 是一个算符("+""-""*" 或 "/"),或是在范围 [-200, 200] 内的一个整数

逆波兰表达式:

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

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

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

就名字比较唬人,自己看代码吧,实在看不懂就留言或者私信,第一时间解答,我里面有个常数项的优化,面试基本不看,能看懂就看,看不懂就不看把,无所谓的,我就是看到超过20%多的人看不过去,改了一下

class Solution {
    /**这狗屁名字真的是有点唬人,我简单解释一下:逆波兰表达式就是操作数在前,运算法在后的表达式
    比如我们平时是1+2,逆波兰就是1 2 + 
    本题给出的所有的tokens里要么是操作数要么是操作符
    我们判断如果是操作数就入栈,如果是操作符就把栈里的弹出计算 */
    public int evalRPN2(String[] tokens) {
        /**如果只有一个操作符,那它肯定是个数,直接转成int返回 */
        if(tokens.length == 1) {
            return Integer.parseInt(tokens[0]);
        }
        /**建立一个操作数栈,Integer类型,如果不是+ - * /就入栈
        如果是就弹出求解*/
        Stack<Integer> stack = new Stack<>();
        for(String token : tokens) {
            /**如果是操作符,弹出两个数计算 */
            if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) {
                int result = calculate(token, stack.pop(), stack.pop());
                /**计算完再放进去,最后从栈里取 */
                stack.push(result);
            } else {
                /**数字直接入栈 */
                stack.push(Integer.parseInt(token));
            }
        }
        return stack.peek();
    }
    /**进行结算的函数*/
    public int calculate(String operator, int num1, int num2) {
        int result = 0;
        /**这里要注意我们先弹出来的是num1,后弹出的是num2
        加和乘无所谓,减和除的时候一定要注意num1在前面 */
        switch(operator) {
            case "+":
                result =  num1 + num2;
                break;
            case "-":
                result = num2 - num1;
                break;
            case "*":
                result = num1 * num2;
                break;
            case "/":
                result = num2 / num1;
                break;
        }
        return result;
    }

    /**唉,O(N)的时间复杂度打败那么点人,我擦,我要改造了,真觉得这些破玩意改造个常数时间有啥意义*/
    public int evalRPN(String[] tokens) {
        /**如果只有一个操作符,那它肯定是个数,直接转成int返回 */
        if(tokens.length == 1) {
            return Integer.parseInt(tokens[0]);
        }
        /**使用数组代替栈*/
        int[] stack = new int[tokens.length];
        int validLen = 0;
        for(String token : tokens) {
            /**如果是操作符,弹出两个数计算 */
            if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) {
                int result = calculate(token, stack[--validLen], stack[--validLen]);
                /**计算完再放进去,最后从栈里取 */
                stack[validLen++] = result;
            } else {
                /**数字直接入栈 */
                stack[validLen ++] = Integer.parseInt(token);
            }
        }
        return stack[validLen - 1];
    }

}

Java中使用LeetCode是一种常见的方式来练习和提高算法和数据结构的能力。LeetCode提供了大量的算法目,每个目都有一个特定的要求和限制条件。在解过程中,我们需要按照目要求设计和实现解决方案。 对于JavaLeetCode编程,一般我们会按照以下步骤进行: 1. 阅读目:仔细阅读目的要求和限制条件,理解目的意思。 2. 分析问:根据目的要求和限制条件,考虑可用的算法和数据结构来解决问。可以使用图、树、链表、数组、哈希表等数据结构,以及常见的算法如深度优先搜索、广度优先搜索、动态规划、回溯等。 3. 实现算法:使用Java编写算法的解决方案。根据目的要求,我们可以使用类、方法等来组织和实现代码。 4. 编写测试用例:为了验证解决方案的正确性,编写测试用例是必不可少的。测试用例应该包括各种情况,包括边界情况和一般情况。 5. 运行和测试:运行编写的代码,并使用编写的测试用例进行测试。通过测试用例的执行结果,我们可以判断代码的正确性和性能。 在编写测试用例时,我们应该考虑尽可能多的情况,以确保代码的正确性。测试用例应该包括输入数据和预期输出结果。可以使用JUnit等测试框架来组织和运行测试用例。 总结来说,JavaLeetCode编程需要认真阅读目,分析问,设计具体的解决方案,并使用合适的数据结构和算法进行实现。编写测试用例是验证解决方案正确性的重要步骤,可以使用JUnit等测试框架来辅助进行测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值