🌕🌕 224. 基本计算器

吞佛童子2022年10月10日
  • algorithm
  • Stack
大约 3 分钟

🌕🌕 224. 基本计算器

难度: 🌕🌕

问题描述

img_6.png


解法

class Solution {
    public int calculate(String s) {
        // 思路:
        // 双栈 - 一个栈存放值,一个栈存放运算符
        // 由于运算符只有 +/- ()
        // 因此优先级就是遇到 右括号 则计算括号内的运算,直到遇到左括号,括号里面肯定是 +/- 优先级同级
        int len = s.length();
        LinkedList<Integer> valS = new LinkedList<>();
        LinkedList<Character> singS = new LinkedList<>();
        int index = 0;
        if(s.charAt(0) == '-') {
            valS.push(0); // 防止出现 -2 + 1 这种数字栈不够的情况
        }
        while(index < len) {
            char c = s.charAt(index);
            if(getSingleNumber(c) >= 0) {
                // 数字直接压栈
                int[] tmpArr = getNumber(s, len, index);
                int num = tmpArr[0];
                index = tmpArr[1];
                valS.push(num);
                // System.out.println(index);
            } else if(c == ' ') {
                index ++;
                continue; // 空格继续
            } else if(c == '(') {
                // 左括号直接压栈
                singS.push(c);
                index ++;
            } else if(c == '+' || c == '-') {
                // 符号位压栈前,计算能计算的部分,防止出现 2 - 1 + 1 变成了 1 + 1 - 2 的情况
                while(!singS.isEmpty() && singS.peek() != '(') {
                    char sign = singS.pop();
                    int b = valS.pop();
                    int a = valS.pop();
                    if(sign == '+') {
                        valS.push(a + b);
                    } else {
                        valS.push(a - b);
                    }
                }
                singS.push(c); // 符号位压栈
                if(index > 0 && s.charAt(index - 1) == '(' && c == '-') {
                    // 即 左括号 后面紧跟了 负号
                    valS.push(0);
                }
                index ++;
            } else {
                // 右括号 - 弹栈
                while(singS.peek() != '(') {
                    char sign = singS.pop();
                    int b = valS.pop();
                    int a = valS.pop();
                    if(sign == '+') {
                        valS.push(a + b);
                    } else if(sign == '-') {
                        valS.push(a - b);
                    } 
                }
                singS.pop(); // 弹出与之对应的左括号
                index ++;
            }
        } 
        // 判断 符号栈 中是否还有符号 - 剩下的肯定都是 +/-
        while(!singS.isEmpty()) {
            char sign = singS.pop();
            int b = valS.pop();
            int a = valS.pop();
            if(sign == '+') {
                valS.push(a + b);
            } else if(sign == '-') {
                valS.push(a - b);
            }
        }
        return valS.peek();
    }

    private int[] getNumber(String s, int len, int left) {
        int res = -1;
        int i = left;
        for(; i < len; i ++) {
            int cur = getSingleNumber(s.charAt(i));
            if(cur >= 0) {
                if(res == -1) {
                    res = cur;
                } else {
                    res = res * 10 + cur;
                }
            } else {
                break;
            }
        }
        return new int[]{res, i};
    }

    private int getSingleNumber(char c) {
        if(c >= '0' && c <= '9') {
            return c - '0';
        } else {
            return -1;
        }
    }
}

输出

img_5.png


解法 2 - 进阶[四则计算器含括号]

class Solution {
    public int calculate(String s) {
        // 思路:
        // 双栈 - 一个栈存放值,一个栈存放运算符
        // 运算符含 +/- */  ()
        // 空格 - 继续
        // 数字 - 直接压数字栈
        // 左括号 - 直接压符号栈
        // 右括号 - 依次计算括号内的值,结果压数字栈
        // +-*/ - 在压栈前先将能运算的部分运算出来,即比较优先级,同级 | 低级的可以运算,然后压栈
        // 特别:
        // 当出现 初始为 负号 | 括号内初始为 负号 的情况,需要先压 0 入数字栈
        HashMap<Character, Integer> map = new HashMap<>(); // 保存不同运算符的优先级
        map.put('+', 1);
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);
        map.put('(', 3);
        map.put(')', 3);

        int len = s.length();
        LinkedList<Integer> valS = new LinkedList<>();
        LinkedList<Character> singS = new LinkedList<>();
        int index = 0;
        if(s.charAt(0) == '-') {
            valS.push(0); // 防止出现 -2 + 1 这种数字栈不够的情况
        }
        while(index < len) {
            char c = s.charAt(index);
            if(getSingleNumber(c) >= 0) {
                // 1. 数字直接压栈
                int[] tmpArr = getNumber(s, len, index);
                int num = tmpArr[0];
                index = tmpArr[1];
                valS.push(num);
                // System.out.println(index);
            } else if(c == ' ') {
                // 2. 空格继续
                index ++;
                continue; // 空格继续
            } else if(c == '(') {
                // 3. 左括号直接压栈
                singS.push(c);
                index ++;
            } else if(c == '+' || c == '-') {
                // 符号位压栈前,先计算能计算的部分,即同级 | 高优先级的部分
                while(!singS.isEmpty() && map.get(c) <= map.get(singS.peek())) {
                    cal(singS, valS);
                }
                singS.push(c); // 符号位压栈
                if(index > 0 && s.charAt(index - 1) == '(' && c == '-') {
                    // 即 左括号 后面紧跟了 负号
                    valS.push(0);
                }
                index ++;
            } else {
                // 右括号 - 弹栈
                while(singS.peek() != '(') {
                    cal(singS, valS);
                }
                singS.pop(); // 弹出与之对应的左括号
                index ++;
            }
        } 
        // 判断 符号栈 中是否还有符号 - 剩下的肯定都是 +/-
        while(!singS.isEmpty()) {
            char sign = singS.pop();
            int b = valS.pop();
            int a = valS.pop();
            if(sign == '+') {
                valS.push(a + b);
            } else if(sign == '-') {
                valS.push(a - b);
            }
        }
        return valS.peek();
    }

    private void cal(LinkedList<Character> singS, LinkedList<Integer> valS) {
        char sign = singS.pop();
        int b = valS.pop();
        int a = valS.pop();
        if(sign == '+') {
            valS.push(a + b);
        } else if(sign == '-') {
            valS.push(a - b);
        } else if(sign == '*') {
            valS.push(a * b);
        } else if(sign == '/') {
            valS.push(a / b);
        }
    }

    private int[] getNumber(String s, int len, int left) {
        int res = -1;
        int i = left;
        for(; i < len; i ++) {
            int cur = getSingleNumber(s.charAt(i));
            if(cur >= 0) {
                if(res == -1) {
                    res = cur;
                } else {
                    res = res * 10 + cur;
                }
            } else {
                break;
            }
        }
        return new int[]{res, i};
    }

    private int getSingleNumber(char c) {
        if(c >= '0' && c <= '9') {
            return c - '0';
        } else {
            return -1;
        }
    }
}

输出 2

img_7.png

上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou