AlgoMooc
你已开通华为OD训练营权益,还差最后一步——完成入营激活(兑换课程 + 加飞书 + 登记服务群),即可解锁全部课程与专属服务。去激活 →
← OD 20 天课程

华为 OD 训练营 · 题解精讲

LC224. 基本计算器

LC224. 基本计算器 预习和复习可以查看我的讲解视频。

题目描述

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。 示例 1: 输入:s = "1 + 1" 输出:2 示例 2: 输入:s = " 2-1 + 2 " 输出:3 示例 3: 输入:s = "(1+(4+5+2)-3)+(6+8)" 输出:23 提示: 1 <= s.length <= 3 * 105 s 由数字、'+'、'-'、'('、')'、和 ' ' 组成 s 表示一个有效的表达式

题目解析

解题思路

本题要求计算包含加减和括号的表达式,核心思路是将减法统一为加法(加一个负数),并利用处理括号带来的优先级问题。遍历字符串时,维护当前符号 sign(1 表示正,-1 表示负)和当前括号内的累加结果 res。遇到数字时,将数字乘以当前符号累加到 res;遇到 ( 时,将当前 ressign 压栈,然后重置 ressign 以计算括号内的值;遇到 ) 时,从栈中弹出括号外的符号和结果,将当前括号结果乘以符号后与栈中结果相加。

关键步骤

1. 处理数字:连续数字字符组成完整整数,计算其值后乘以当前符号 sign 累加到 res。 2. 处理 `+` / `-`:更新 sign 为 1 或 -1,表示后续数字的符号。 3. 处理 `(`:将当前 ressign 依次压栈,然后重置 res = 0sign = 1,开始计算括号内表达式。 4. 处理 `)`:弹出栈顶的 formerSignformerRes,将当前括号结果 res 乘以 formerSign 后与 formerRes 相加,得到括号外的结果。


示例:计算 "1-(2+3)"
初始 res=0, sign=1
遇到 1 → res = 0 + 1*1 = 1
遇到 - → sign = -1
遇到 ( → 压栈 res=1, sign=-1;重置 res=0, sign=1
遇到 2 → res = 0 + 2*1 = 2
遇到 + → sign = 1
遇到 3 → res = 2 + 3*1 = 5
遇到 ) → 弹出 formerSign=-1, formerRes=1 → res = 1 + (-1)*5 = -4

复杂度分析

  • 时间复杂度:O(n),其中 n 为字符串长度,每个字符只处理一次。
  • 空间复杂度:O(n),栈在最坏情况下存储所有括号层级的中间结果和符号。

参考代码

# 登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# 基本计算器( LeetCode 224 ):https://leetcode-cn.com/problems/basic-calculator
class Solution:
    def calculate(self, s: str) -> int:

        # 使用栈来储存字符串表达式中的数字
        stack = list()

        # 为了方便计算,所有的操作都视为加法操作
        # 那么原先的减法操作就相当于是加一个负数
        # 默认都是正数
        sign = 1

        # 保存计算的结果
        res = 0

        # 获取字符串的长度,然后获取里面的每个字符
        length = len(s)

        # 从 0 开始访问字符串中的每个字符
        i = 0

        # 获取字符串里面的每个字符
        while i < length:
            # 获取此时的字符
            ch = s[i]

            if ch == ' ' :
                i += 1
            # 如果当前字符是数字的话
            elif ch.isdigit() :
                # 那么把获取到的数累加到结果 res 上
                value = ord(s[i]) - ord('0')

                # 去查看当前字符的后一位是否存在
                # 如果操作并且后一位依旧是数字,那么就需要把后面的数字累加上来
                while i + 1 < length and s[i + 1].isdigit():
                    i += 1
                    value = value * 10 + ord(s[i]) - ord('0')
                    
                # 那么把获取到的数累加到结果 res 上
                res += value * sign

                i += 1

              # 如果是 '+'
            elif ch == '+' :
                # 那么说明直接加一个正数
                sign = 1

                i += 1

              # 如果是 '-'
            elif ch == '-' :

                # 那么说明加一个负数
                sign = -1

                i += 1

              # 如果是 '('
            elif ch == '(' :
                # 根据数学计算规则,需要先计算括号里面的数字
                # 而什么时候计算呢?
                # 遇到 ) 为止
                # 所以,在遇到 ) 之前需要把之前计算好的结果存储起来再计算
                # ( ) 直接的计算规则和一开始是一样的

                # 1、先把 ( 之前的结果存放到栈中
                stack.append(res)

                # 2、重新初始化 res 为 0
                res = 0
                # 3、把 ( 左边的操作符号存放到栈中
                # 比如如果是 5 - ( 2 + 3 ) ,那么就是把 -1 存放进去
                # 比如如果是 5 +( 2 + 3 ) ,那么就是把 1 存放进去
                stack.append(sign)

                # 4、为了方便计算,所有的操作都视为加法操作
                # 那么原先的减法操作就相当于是加一个负数
                # 默认都是正数
                sign = 1

                i += 1

                # 如果是 ')'
            elif ch == ')' :
                
                # 那么就需要把栈中存放的元素取出来了
                # 在 ch == '(' 这个判断语句中,每次都会往栈中存放两个元素
                # 1、先存放左括号外面的结果
                # 2、再存放左括号外面的符号

                # 1、先获取栈顶元素,即左括号外面的符号,查看是 + 还是 -
                # 把栈顶元素弹出
                formerSign = stack.pop()

                # 2、再获取栈顶元素,即左括号结果
                # 把栈顶元素弹出
                formerRes = stack.pop()

                # 那结果就是括号外面的结果 + 括号里面的结果,至于是加正数还是负数,取决于左括号外面的符号
                res = formerRes +  formerSign * res 

                i += 1
             

        # 返回计算好的结果
        return res

四、复杂度分析
时间复杂度:O(n),其中 n 为字符串 s 的长度。需要遍历字符串 s 一次,计算表达式的值。
空间复杂度:O(n),其中 n 为字符串 s 的长度。空间复杂度主要取决于栈的空间,栈中的元素数量不超过 n。
五、直接调API解法
如果上述内容实在学得吃力,但机试中又不幸遇到。可以直接使用内置函数eval()解题。内置函数eval()能够直接计算一个字符串表达式的值,能够识别加减乘除以及括号。
s = input()
print(eval(s))