题解 | #表达式求值#

表达式求值

https://www.nowcoder.com/practice/9566499a2e1546c0a257e885dfdbf30d

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.Scanner;

public class Main {
    static Map<Character, Integer> map = new HashMap<>();
    static{//为运算符映射优先级,后面判断运算符压栈时需要用到
        map.put('(', -1);
        map.put('+', 0);
        map.put('-', 0);
        map.put('*', 1);
        map.put('/', 1);
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] exp = in.next().toCharArray();
        in.close();
        //char[] exp = "(7+5*4*3+6)".toCharArray();
        Stack<Character> opeStack = new Stack<>();
        Stack<Integer> numStack = new Stack<>();
        boolean continueNum = false;//用来辅助判断是否存在连续的数字字符,每当迭代到数字字符则置真,迭代到非数字字符则置假
        boolean negativeNum = false;//为真则表示本次数字要乘以-1,假则不用乘
        char preChar = '@';//表示上一个字符,用来辅助判断‘-’是减号还是负号,处在字符串开头或者左括号右边的‘-’,都应是负号
        for(char c: exp){
            //如果字符为操作数,则压入操作数栈
            if(Character.isDigit(c)){
                if(!continueNum){//如果上一个字符为非数字字符则压栈
                    if(negativeNum){//如果上一个字符是‘-’,且判断出来是负号,而不是减号,则数字应是负数
                        numStack.push(-1 * (c - '0'));
                        negativeNum = false;
                    }else {//正数压栈
                        numStack.push(c - '0');
                    }
                    continueNum = true;//置为真,如果下一个字符还是数字的话,根据这个布尔值可以正确处理连续的数字字符
                }else{//如果上一个字符是数字字符,则把上一个压栈数字弹出乘以十再加上当前数字再压栈
                    numStack.push(numStack.pop() * 10 + (c - '0'));
                }
            } else {
                continueNum = false;
                //如果之前的字符是@或者(,且当前的字符为‘-’,则当前‘-’字符不是运算符,是负号
                if((preChar == '@' || preChar =='(') && c == '-'){
                    negativeNum = true;
                }else if(opeStack.isEmpty() && c != '-' || c == '('){//如果运算符栈顶为空或者是左括号,则直接把新运算符压入运算符栈
                    opeStack.push(c);
                }else if(c == ')'){//如果是右括号,则一直执行计算,直到遇到左括号为止
                    while(opeStack.peek() != '('){
                        cal(opeStack, numStack);
                    }
                    //弹出左括号
                    opeStack.pop();
                }else {
                    //运算符栈不为空且当前字符不是‘-’,判断两运算符优先级
                    while(true){//如果旧运算符比新运算符优先级更高,则不断弹出旧运算符并执行,直到新运算符优先级更高或者运算符栈为空为止
                        if(opeStack.isEmpty()) break;
                        char oldOpe = opeStack.peek();
                        //如果旧运算符等级大于等于新运算符等级,则先执行旧运算符的运算,否则不执行计算
                        if(map.get(oldOpe) >= map.get(c)) {
                            cal(opeStack, numStack);
                        }else{
                            break;
                        }
                    }
                    //再把新操作符压入运算符栈
                    opeStack.push(c);
                }
            }
            preChar = c;
        }
        //迭代完字符串后,可能只把最后一个数字压栈,就没有继续操作运算符栈里的操作符了,所以这里要做最后的计算
        while(!opeStack.isEmpty()){
            cal(opeStack, numStack);
        }
        System.out.println(numStack.pop());
    }

    /**
     * 弹出操作数栈两个数,弹出运算符栈一个运算符,执行计算并把最终计算的值压栈
     * @param opeStack 运算符栈
     * @param numStack 操作数栈
     */
    static void cal(Stack<Character> opeStack, Stack<Integer> numStack){
        char ope = opeStack.pop();
        int y = numStack.pop();
        int x = numStack.pop();
        int z = 0;
        if(ope == '+'){
            z = x + y;
        }else if(ope == '-'){
            z = x - y;
        }else if(ope == '*'){
            z = x * y;
        }else if(ope == '/'){
            z = x / y;
        }
        numStack.push(z);
    }
}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务