LeetCode-EvalRPN逆波兰表达式求值

题目要求:

/**
 * @author yangshuo
 * @date 2020/3/23 14:11
 *
 * 逆波兰表达式求值
 *
 * 根据逆波兰表示法,求表达式的值。
 *
 * 有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
 *
 * 说明:
 *
 *     整数除法只保留整数部分。
 *     给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
 *
 * 示例 1:
 *
 * 输入: ["2", "1", "+", "3", "*"]
 * 输出: 9
 * 解释: ((2 + 1) * 3) = 9
 *
 * 示例 2:
 *
 * 输入: ["4", "13", "5", "/", "+"]
 * 输出: 6
 * 解释: (4 + (13 / 5)) = 6
 *
 * 示例 3:
 *
 * 输入: ["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
 */

初步解法:

刚开始的第一个想法是利用栈来实现,这也是逆波兰表达式的官方解法。遇见数字压栈,遇见运算符出栈两个数字计算即可。

代码:

public int evalRPN(String[] tokens) {
        // 设置栈
        Stack<Integer> stack = new Stack<>();
        // 设置一个集合保存运算符
        Set<String> set = new HashSet<>();
        set.add("+");
        set.add("-");
        set.add("*");
        set.add("/");

        for (int i= 0; i < tokens.length; i++){
            // 如果是运算符就出栈两个数字做计算
            if (set.contains(tokens[i])){
                int right = stack.pop();
                int left = stack.pop();
                int calculation = calculation(left, right, tokens[i]);
                stack.add(calculation);
            }else{
                // 如果不是就压栈
                stack.add(Integer.valueOf(tokens[i]));
            }
        }

        // 最后栈顶的元素肯定是最后的计算结果
        return stack.peek();

    }

    private int calculation(int left, int right, String operator){
        switch (operator){
            case "+":
                return left + right;
            case "-":
                return left - right;
            case "*":
                return left * right;
            case "/":
                return left / right;
            default:
                return 0;
        }
    }

执行结果:

速度还算可以击败86.47%,内存占用特别高,还是有优化的空间。不过后面的执行都是41.4MB大概leetcode出错了吧,但是可以肯定的是肯定还有更好的办法。

优化解法:

根据给的示例,观察发现如果能够记住每次括号的位置,这样就计算后括号左移就能计算出最终结果,但是不能计算比较复杂的情况比如(a+b)*(c+d),之后就是一般的优化代码的方式,先套用进去,先是从后往前遍历看有没有规律可寻,可惜我没有看出来有什么不同,但是最优解的大神能看出来,后面大家可以看一下,他是如何击败100%的。

第二点就是寻找从前往后找的规律,把图示画出来就能发现,每次遍历的n-1和n-2的位置可以复用,这样做就可以节省栈的开销,速度和内存都是得到提升。

代码如下:

public int evalRPN(String[] tokens) {

        // 将栈的结构用数组代替
        int [] stack = new int[tokens.length/ 2 + 1];
        int index = 0;
        for (String s : tokens){
            // 每次做运算,将之前已经参加过运算的index -1 和 index -2 的值覆盖掉,这里计算完毕覆盖index-2的值
            switch (s){
                case "+":
                    stack[index - 2] += stack[index-1];
                    index --;
                    break;
                case "-":
                    stack[index - 2] -= stack[index-1];
                    index --;
                    break;
                case "*":
                    stack[index - 2] *= stack[index-1];
                    index --;
                    break;
                case "/":
                    stack[index - 2] /= stack[index-1];
                    index --;
                    break;
                default:
                    // 这里由于index++的性质,所以覆盖的实际上是上一步index-- 后的值
                    stack[index ++] = Integer.parseInt(s);
            }
        }

        // 最后栈顶的元素肯定是最后的计算结果
        return stack[0];

    }

 执行结果:

比之前提升了4ms,但是只击败了99.7%。

可能leetCode出错了,这里显示的内存没有发生变化,实际上这个解答和击败100%内存的解答是一致的。

 

终极解法:

不知道哪位大神想出来的递归解法,可以观摩一下

public int evalRPN(String[] tokens) {
           index = tokens.length - 1;
        return getPrefix(tokens);
    }

     int index;

    public  int getPrefix(String[] tokens) {
        String token = tokens[index--];
        if (token.equals("+")) {
            int prefix1 = getPrefix(tokens);
            int prefix0 = getPrefix(tokens);
            return prefix0 + prefix1;
        } else if (token.equals("-")) {
            int prefix1 = getPrefix(tokens);
            int prefix0 = getPrefix(tokens);
            return prefix0 - prefix1;
        } else if (token.equals("*")) {
            int prefix1 = getPrefix(tokens);
            int prefix0 = getPrefix(tokens);
            return prefix0 * prefix1;
        } else if (token.equals("/")) {
            int prefix1 = getPrefix(tokens);
            int prefix0 = getPrefix(tokens);
            return prefix0 / prefix1;
        } else {
            return Integer.parseInt(token);
        }
    }

 

微信公众号:二虎程序

LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值