夯实算法-基本计算器 II

117 阅读2分钟

题目:基本计算器 II

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。

注意: 不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入: s = "3+2*2"
输出: 7

示例 2:

输入: s = " 3/2 "
输出: 1

示例 3:

输入: s = " 3+5 / 2 "
输出: 5

提示:

  • 1<=s.length<=31051 <= s.length <= 3 * 10^5
  • s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
  • s 表示一个 有效表达式
  • 表达式中的所有整数都是非负整数,且在范围 [0,2311][0, 2^{31} - 1] 内
  • 题目数据保证答案是一个 32-bit 整数

解题思路

准备一个数组,用于保存逆波兰表达式 准备一个栈,用于保存运算符 准备一个 StringBuilder 对象,用于拼接字符串的连续数字

注意点 1.字符串的连续数字问题 2.遍历结束,最后一个数字需要放入数组,且栈中剩余运算符也要放入数组 3.遇到空格,不做任何处理

使用两个栈:

  1. 一个栈存放操作符,另一个存放数字
  2. 当本次的操作符优先级低于上一个时,将前面的所有数字弹出,计算得到一个结果,压栈,即calculateBefore函数
  3. 若本次的操作符优先级与上次相等,那么从栈中弹出两个数字和一个操作符,进行计算,然后将结果压栈,即calculatePart函数
  4. 结果即为栈中的最后留下的那个数

代码实现

private static final Map < Character, Integer > priorityMap;
private Deque < Integer > numStack;
private Deque < Character > operateStack;

static {
    priorityMap = new HashMap < > ();
    priorityMap.put('*', 0);
    priorityMap.put('/', 0);
    priorityMap.put('+', 1);
    priorityMap.put('-', 1);
}

public int calculate(String s) {
    numStack = new LinkedList < > ();
    operateStack = new LinkedList < > ();
    int n = s.length();
    int i = 0;
    while (i < n) {
        if (s.charAt(i) == ' ') {
            ++i;
        } else if (Character.isDigit(s.charAt(i))) {
            int num = 0;
            while (i < n && Character.isDigit(s.charAt(i))) {
                num = num * 10 + s.charAt(i) - '0';
                ++i;
            }
            numStack.push(num);
        } else {
            if (operateStack.isEmpty()) {
                operateStack.push(s.charAt(i));
            } else {
                char lastSign = operateStack.peek();
                if (priorityMap.get(s.charAt(i)) > priorityMap.get(lastSign)) {
                    calculateBefore();
                } else if (Objects.equals(priorityMap.get(s.charAt(i)), priorityMap.get(lastSign))) {
                    calculatePart();
                }
                operateStack.push(s.charAt(i));
            }
            ++i;
        }
    }
    calculateBefore();
    return numStack.pop();
}

// 计算栈中所有操作符的结果,并将结果压栈
public void calculateBefore() {
    while (!operateStack.isEmpty()) {
        calculatePart();
    }
}

// 计算前一个操作符的结果,并将结果压栈
public void calculatePart() {
    int afterNum = numStack.pop();
    int beforeNum = numStack.pop();
    int result = forDifferentSign(beforeNum, afterNum, operateStack.pop());
    numStack.push(result);
}

public int forDifferentSign(int a, int b, char sign) {
    switch (sign) {
        case '*':
            return a * b;
        case '/':
            return a / b;
        case '+':
            return a + b;
        case '-':
            return a - b;
        default:
            return 0;
    }
}

运行结果

Snipaste_2023-04-29_23-50-15.png

复杂度分析

  • 空间复杂度:O(n)
  • 时间复杂度:O(n)

掘金(JUEJIN) 一起分享知识, Keep Learning!