224. 基本计算器
题目含义:实现一个基本的计算器,计算一个字符串表达式 s
并返回其值。s
由数字、+
、-
、(
、)
、和空格组成,而且 -(2 + 3)
这样的表达式是有效的。
在这个表达式中除了括号外,运算符就只有 +
和 -
。因此我们可以使用双栈来实现一个计算器,这两栈分别存储数字和运算符,分别记为 numSt
和 opsSt
。
此外,我们需要额外考虑 -(-1+5)
和 -6
这种情况。这两种情况对应了 -
是字符串 s
的第一个字符或在 (
的后面,那么我们在numSt
添加数字 0
,则表达式就变成了 0-6
和 0-(0-1+5)
。
考虑完特殊情况,我们现在对表达式 s
从前往后遍历,将数字字符和运算符字符分开处理。假设当前遍历到的元素是 c = s[i]
:
c
是(
:直接放进opsSt
栈中;c
是)
:计算现有的opsSt
和numSt
,直到遇到)
停止计算,将计算结果是放进numSt
中,最后把栈顶元素)
弹出;c
是数字字符:若这个字符为5255
,那么我们需要利用while
获取整个数字,然后存进numSt
中;c
是运算符字符,根据上面讨论的情况,我们需要判断符号-
是否在第一个位置或在(
后面,即i==0 or s[i-1] in '('
;接下来在添加新的运算符之前,可以先把现有的数字和运算符进行计算,再执行opsSt.append(c)
;
当遍历完整个表达式,如果 opsSt
栈不为空,则我们把现有的元素继续计算;最后返回 numSt
的栈顶元素。
class Solution:
def calculate(self, s: str) -> int:
# (1+(4+555+2)-3)+(-6+8) 555 和 -6
numSt, opsSt = [], []
s = s.replace(" ", "") # 将所有的空格删除
def calc():
if len(numSt) < 2 or not opsSt:
return
b, a, op = numSt.pop(), numSt.pop(), opsSt.pop() # 注意a和b的位置
numSt.append(a+b if op == '+' else a-b)
i = 0
while i < len(s):
c = s[i]
if c == '(':
opsSt.append(c)
elif c == ')':
while opsSt and opsSt[-1] != '(':
calc()
opsSt.pop() # == '('
else:
if c.isdigit():
num = 0
while i < len(s) and s[i].isdigit():
num, i = num * 10 + int(s[i]), i+1
numSt.append(num)
i -= 1
else:
# -(-4+5+2)
if c in '-' and (i == 0 or s[i-1] in '('):
numSt.append(0)
while opsSt and opsSt[-1] != '(':
calc()
opsSt.append(c)
i += 1
while opsSt:
calc()
return numSt[-1]
/**
* @param {string} s
* @return {number}
*/
var calculate = function(s) {
s = s.replace(/\s*/g, ''); // 返回一个新的字符串
const numSt = [], opSt = [];
const calc = () => {
if (numSt.length < 2 || opSt.length === 0) return;
const b = numSt.pop(), a = numSt.pop(), op = opSt.pop();
numSt.push(op === '-' ? a - b : a + b);
}
const n = s.length;
for (let i=0; i < n; i++) {
const c = s[i];
if (c === '(') opSt.push(c);
else if (c === ')') {
while (opSt.length > 0 && opSt.at(-1) !== '(') calc();
opSt.pop(); // 移除 '('
}
else {
if (/^[0-9]$/.test(c)) {
let num = 0;
// 从 s[i] 开始处理
while (i < n && /^[0-9]$/.test(s[i])) num = num * 10 + Number(s[i]), i++;
numSt.push(num);
i--;
} else {
if (c === '-' && (i === 0 || s[i-1] === '(')) numSt.push(0);
while (opSt.length > 0 && opSt.at(-1) != '(') calc();
opSt.push(c);
}
}
}
while (opSt.length > 0) calc();
return numSt.at(-1);
};