LeetCode 772. 基本计算器 III

772. 基本计算器 III

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

表达式字符串只包含非负整数,算符 +-*/ ,左括号 ( 和右括号 ) 。整数除法需要 向下截断 。

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

注意:你不能使用任何将字符串作为表达式求值的内置函数,比如 eval() 。

示例 1:

输入:s = "1+1"
输出:2

示例 2:

输入:s = "6-4/2"
输出:4

示例 3:

输入:s = "2*(5+5*2)/3+(6/2+8)"
输出:21

提示:

  • 1 <= s <= 10^4
  • s 由整数、'+''-''*''/''(' 和 ')' 组成
  • s 是一个 有效的 表达式

解法1: 栈

同类题型详解:LeetCode 224. 基本计算器-CSDN博客

LeetCode 227. 基本计算器 II-CSDN博客

解题思路

解决这个问题的关键在于使用两个栈:一个用于存储操作符(opStack),另一个用于存储操作数(numStack)。通过模拟运算过程,我们可以逐步计算表达式的值。

算法逻辑

  1. 初始化两个栈:一个用于存储操作符,另一个用于存储整数。
  2. 遍历表达式:逐个字符读取表达式字符串。
  3. 处理数字:当遇到数字时,将其转换成整数并压入numStack
  4. 处理操作符
    • 如果是左括号'(',压入操作符栈。
    • 如果是右括号')',执行操作直到遇到左括号,并将结果压入numStack
    • 如果是操作符(+, -, *, /),先执行栈中的操作直到遇到左括号或优先级更低的操作符,然后将当前操作符压栈。
  5. 执行操作:弹出操作符和相应的操作数,执行相应的运算,并将结果压回numStack
  6. 最终计算:遍历结束后,执行栈中剩余的操作,得到最终结果。

算法实现步骤

  1. 定义calculate函数,接收一个字符串s作为参数。
  2. 定义辅助函数stackHigher,用来判断当前操作符是否比栈顶的操作符优先级更高。
  3. 初始化操作符栈opStack和操作数栈numStack
  4. 遍历字符串s
    • 如果当前字符是数字,将其转换为整数并压入numStack
    • 如果是左括号'(',直接压入opStack
    • 如果是右括号')',执行操作直到遇到左括号,并将结果压入numStack,然后弹出左括号。
    • 如果是操作符,先判断是否需要执行栈中已有的操作,然后将当前操作符压入opStack
  5. 处理完所有字符后,继续执行栈中的操作直到opStack为空。
  6. 返回numStack的栈顶元素,即为表达式的计算结果。

Java版:

class Solution {
    public int calculate(String s) {
        Deque<Character> opStack = new ArrayDeque<>();
        Deque<Integer> numStack = new ArrayDeque<>();
        s = s.replaceAll(" ", "");
        int n = s.length();
        int i = 0;
        while (i < n) {
            char c = s.charAt(i);
            if (c == '(') {
                opStack.push(c);
            } else if (c == ')') {
                while (!opStack.isEmpty() && opStack.peek() != '(') {
                    char op = opStack.pop();
                    int num2 = numStack.pop();
                    int num1 = numStack.pop();
                    switch (op) {
                        case '+':
                            numStack.push(num1 + num2);
                            break;
                        case '-':
                            numStack.push(num1 - num2);
                            break;
                        case '*':
                            numStack.push(num1 * num2);
                            break;
                        case '/':
                            numStack.push(num1 / num2);
                            break;
                    }
                }
                opStack.pop();
            } else if (Character.isDigit(c)) {
                int num = 0;
                while (i < n && Character.isDigit(s.charAt(i))) {
                    num = num * 10 + (s.charAt(i) - '0');
                    i++;
                }
                i--;
                numStack.push(num);
            } else {
                while (!opStack.isEmpty() && opStack.peek() != '(' && stackHigher(c, opStack.peek())) {
                    char op = opStack.pop();
                    int num2 = numStack.pop();
                    int num1 = numStack.pop();
                    switch (op) {
                        case '+':
                            numStack.push(num1 + num2);
                            break;
                        case '-':
                            numStack.push(num1 - num2);
                            break;
                        case '*':
                            numStack.push(num1 * num2);
                            break;
                        case '/':
                            numStack.push(num1 / num2);
                            break;
                    }
                }
                opStack.push(c);
            }
            i++;
        }

        while (!opStack.isEmpty() ) {
            char op = opStack.pop();
            int num2 = numStack.pop();
            int num1 = numStack.pop();
            switch (op) {
                case '+':
                    numStack.push(num1 + num2);
                    break;
                case '-':
                    numStack.push(num1 - num2);
                    break;
                case '*':
                    numStack.push(num1 * num2);
                    break;
                case '/':
                    numStack.push(num1 / num2);
                    break;
            }
        }
        return numStack.peek();
    }

    private boolean stackHigher(char c, char peek) {
        if ((c == '*' || c == '/') && (peek == '+' || peek == '-')) {
            return false;
        }
        return true;
    }
}

Python3版:

class Solution:
    def calculate(self, s: str) -> int:
        def stackHigher(c, peek):
            if c in '*/' and peek in '+-':
                return False
            return True

        opStack = []
        numStack = []
        i = 0
        n = len(s)
        while i < n:
            if s[i] == '(':
                opStack.append(s[i])
            elif s[i] == ')':
                while opStack and opStack[-1] != '(':
                    op = opStack.pop()
                    num2 = numStack.pop()
                    num1 = numStack.pop()
                    match op:
                        case '+':
                            numStack.append(num1 + num2)
                        case '-':
                            numStack.append(num1 - num2)
                        case '*':
                            numStack.append(num1 * num2)
                        case '/':
                            numStack.append(int(num1 / num2))
                opStack.pop()
            elif s[i].isdigit():
                num = 0
                while i < n and s[i].isdigit():
                    num = num * 10 + int(s[i])
                    i += 1
                i -= 1
                numStack.append(num)
            else:
                while opStack and opStack[-1] != '(' and stackHigher(s[i], opStack[-1]):
                    op = opStack.pop()
                    num2 = numStack.pop()
                    num1 = numStack.pop()
                    match op:
                        case '+':
                            numStack.append(num1 + num2)
                        case '-':
                            numStack.append(num1 - num2)
                        case '*':
                            numStack.append(num1 * num2)
                        case '/':
                            numStack.append(int(num1 / num2))
                opStack.append(s[i])
            i += 1

        while opStack:
            op = opStack.pop()
            num2 = numStack.pop()
            num1 = numStack.pop()
            match op:
                case '+':
                    numStack.append(num1 + num2)
                case '-':
                    numStack.append(num1 - num2)
                case '*':
                    numStack.append(num1 * num2)
                case '/':
                    numStack.append(int(num1 / num2))
        
        return numStack[-1]
        

复杂度分析

  • 时间复杂度:O(n),其中n是表达式字符串的长度。每个字符只被遍历和处理一次。
  • 空间复杂度:O(n),最坏情况下,所有字符都可能被存储在栈中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值