[LeetCode-224]基本计算器

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。

原题链接:https://leetcode-cn.com/problems/basic-calculator/

示例 1:
输入: “1 + 1”
输出: 2

示例 2:
输入: " 2-1 + 2 "
输出: 3

示例 3:
输入: “(1+(4+5+2)-3)+(6+8)”
输出: 23

说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。


思路:中缀表达式转后缀表达式+后缀表达式计算结果

中缀表达式转后缀表达式

  • 从左到右遍历中缀表达式,如果是数字,就添加到后缀表达式中
  • 如果是符号,就判断运算符栈是否为空;如果为空,就直接添加到运算符栈中
    如果不为空,就判断其与运算符栈顶元素的优先级,是右括号或者低于栈顶运算符优先级,就依次出栈,并将当前运算符入栈;
  • 重复上一步操作,直至中缀表达式遍历完成
  • 判断栈中是否为空。如果不为空,就依次取出栈顶元素放到后缀表达式中,直到栈中为空

后缀表达式计算结果

  • 准备一个数字栈。从左到右依次遍历后缀表达式,如果是数字,就放入栈中;
  • 如果是运算符,就从栈中弹出两个数字,第一个取出的数字为右运算数,第二个取出的数字为左运算数,进行运算,并将结果压入栈中
  • 重复操作,直至后缀表达式遍历完成,栈中的数字就是表达式的结果

时间复杂度和空间复杂度均为O(N),其中N为字符串的长度。

代码:

 public int calculate(String s) {
        StringBuilder stringBuilder = toSuffix(s);
        String[] strings = stringBuilder.toString().split(" ");
        int result = getValueOfExpression(strings);

        return result;
    }

    /**
     * 获取表达式的值
     * @param strings 每一个string字符串为数字或者运算符
     * @return  返回表达式的结果
     */
    private int getValueOfExpression(String[] strings) {

        //数字栈用来保存运算数字
        Stack<Integer> numStack = new Stack<>();
        for (int i = 0; i < strings.length; i++) {

            //当字符是加号时,从栈中弹出两个数字,进行运算并且把结果放回栈中
            if (strings[i].charAt(0) == '+'){
                int num1 = numStack.pop();
                int num2 = numStack.pop();
                numStack.push(num2+num1);
            }else if(strings[i].charAt(0) == '-'){
                //当字符是减号时,从栈中弹出两个数字,进行运算并且把结果放回栈中
                int num1 = numStack.pop();
                int num2 = numStack.pop();
                numStack.push(num2-num1);
            }else{
                //当字符串是数字时,将数字压入栈中
                numStack.push(Integer.parseInt(strings[i]));
            }
            
        }
        //返回栈中最后的结果
        return numStack.pop();
    }

    /**
     * 将中缀表达式转化为后缀表达式
     * @param s 中缀表达式
     * @return  后缀表达式
     */
    private  StringBuilder toSuffix(String s){
        //用来保存后缀表达式
        StringBuilder sb = new StringBuilder();
        //保存运算符
        Stack<Character> operatorStack = new Stack<>();
        for (int i = 0; i < s.length();) {

            char temp = s.charAt(i);
            //如果是数字,就把数字的连续数字都取出来,并且是空格分隔
            if (isNumber(temp)){
                int[] result = getNumAndEndIndex(s, i);
                sb.append(result[0]);
                sb.append(" ");
                i = result[1];
            }else if(temp == '('){
                //如果是左括号,直接压入栈中
                operatorStack.push(temp);
                i++;
            }else if(temp == '+' || temp == '-'){
                //如果时+或-,并且栈内不为空
                if (!operatorStack.isEmpty()){
                    while (!operatorStack.isEmpty()){
                        char item = operatorStack.pop();
                        //如果是栈顶是左括号,直接推入栈中,并且结束循环
                        if (item == '('){
                            operatorStack.push(item);
                            break;
                        }else{
                            //否则就添加到StringBuilder中
                            sb.append(item);
                            sb.append(" ");
                        }
                    }
                }
                //并且把符号压入栈中
                operatorStack.push(temp);
                i++;
            }else if(temp == ')'){
                //如果是右括号,就一直出栈,直到栈顶为左括号
                char item = operatorStack.pop();
                while(item != '('){
                    sb.append(item);
                    sb.append(" ");
                    item = operatorStack.pop();
                }
                i++;
            }else{
                i++;
            }
        }

        //如果栈内不为空,就一直出栈
        while (!operatorStack.isEmpty()){
            sb.append(operatorStack.pop());
            sb.append(" ");
        }
        return sb;
    }

    /**
     * 获取字符串的数字以及结束的索引
     * @param s 字符串
     * @param i 数字开始的索引
     * @return  数组:下标0代表数字,下标1代表结束的索引
     */
    private int[] getNumAndEndIndex(String s, int i) {

        //保存数字以及结束的索引
        int num = 0;
        int index = i;
        for (; index < s.length(); index++) {
            if (isNumber(s.charAt(index))){
                num = num * 10 + s.charAt(index) - '0';
            }else{
                break;
            }
        }
        int[] result = new int[2];
        result[0] = num;
        result[1] = index;
        return result;
    }

    /**
     * 判断字符是否为数字
     * @param c 字符
     * @return  是否为数字
     */
    private boolean isNumber(char c){
        if(c >= '0' && c <= '9')
            return true;
        return false;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值