227. 基本计算器 II Medium
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例 1:
输入:s = "3+2*2"
输出:7
示例 2:
输入:s = " 3/2 "
输出:1
示例 3:
输入:s = " 3+5 / 2 "
输出:5
解题思路
输入:一个字符串表达式 s
输出:返回该表达式的计算结果(只包含非负整数和运算符 + - * /
,无括号)
本题属于 表达式解析栈 问题。
我们可以通过遍历字符串,结合栈结构和运算符优先级来实现:
思路步骤:
使用变量
num
构造当前的数字(支持多位数)。使用
prev_op
记录上一个运算符,初始设为'+'
,默认第一个数字作为正数处理。使用栈
stack
存储每一步的阶段性结果(用于加减/乘除处理顺序)。遍历字符串:
如果是数字,就更新
num = num * 10 + int(c)
。如果遇到操作符或到达末尾,就根据
prev_op
来处理当前数字:'+'
:将num
入栈;'-'
:将-num
入栈;'*'
:弹出栈顶与num
相乘后入栈;'/'
:弹出栈顶与num
相除(注意向零取整)后入栈。
更新
prev_op = 当前操作符
,并将num
重置为 0。
最后返回栈中所有元素的和作为最终结果。
代码实现
python
class Solution:
def calculate(self, s: str) -> int:
num = 0 # 当前正在构建的数字(可能是多位数)
stack = [] # 栈,用于保存每一段的计算结果
prev_op = '+' # 记录上一个操作符,初始为 '+'(默认第一个数为正)
# 遍历字符串每个字符
for i in range(len(s)):
c = s[i]
# 如果是数字字符,累加到当前数字中
if c.isdigit():
num = num * 10 + int(c)
# 如果遇到操作符(+ - * /),或者到了字符串末尾
if (not c.isdigit() and c != ' ') or i == len(s) - 1:
# 根据上一个操作符处理当前的 num
if prev_op == '+':
stack.append(num) # 加号:当前数字直接入栈
elif prev_op == '-':
stack.append(-num) # 减号:将当前数字变成负数后入栈
elif prev_op == '*':
stack.append(stack.pop() * num) # 乘法:弹出栈顶元素乘以当前数字
elif prev_op == '/':
# 除法:注意要向零取整(例如 -3 / 2 应为 -1,而不是 -2)
stack.append(int(stack.pop() / num))
prev_op = c # 更新当前操作符为这次遇到的操作符
num = 0 # 重置当前数字,准备读取下一个数
# 最终栈中所有数字相加得到结果
return sum(stack)
javascript
/**
* @param {string} s
* @return {number}
*/
const calculate = function(s) {
let num = 0;
let stack = [];
let prev_op = '+';
for (let i in s) {
const c = s[i];
if (/[0-9]/.test(c)) num = num * 10 + Number(c);
if (!/[0-9]/.test(c) && c !== ' ' || i == s.length - 1) {
if (prev_op == '+') stack.push(num);
if (prev_op == '-') stack.push(-num);
if (prev_op == '*') stack.push(stack.pop() * num);
if (prev_op == '/') stack.push(parseInt(stack.pop() / num));
num = 0;
prev_op = c;
}
}
return stack.reduce((acc, curr) => acc + curr, 0);
};
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)