Skip to main content

基本计算器

题目

Implement a basic calculator to evaluate a simple expression string.

The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero.

Example 1:

Input: "3+2*2"
Output: 7

Example 2:

Input: " 3/2 "
Output: 1

Example 3:

Input: " 3+5 / 2 "
Output: 5

Note:

  • You may assume that the given expression is always valid.
  • Do not use the eval built-in library function.

思路

字符串转整数

我们先看下字符串是如何转整数的,因为字符串表达式中间可能不是一位数,而是多位数,比如 1 + 23,其中 23 是一个两位数,读取的时候,先读到 2,要将其先转成整数存储下来,然后读到 3 的时候再将其放到个位:

s = '23'

num = 0
for c in s:
num = 10 * num + int(c)

print(num) # 23

加减

YK3TXz
caution

不只是遇到新的符号会触发入栈,当遍历到了字符串的最后一个字符,也应该将前面的数字入栈,方便后续计算最终结果。

zWXjsM

为了前后统一,可以在原始字符串后面直接加上 +

for (let c of s + '+')

乘除

7BDGNq

小结

遍历算式字符串,因为运算符有优先级,使用栈来存储每一次的运算结果。每次将运算符和其对应的算数计算后入栈,如果遇到高优先级的运算符,和栈顶元素运算完后再入栈。

代码实现

/**
* @param {string} s
* @return {number}
*/
var calculate = function (s) {
let num = 0;
let operator = '+';
let stack = [];
for (let c of s + '+') {
// '+'
if (c >= '0' && c <= '9') {
num = num * 10 + +c;
continue;
}
if (c !== ' ') {
// 表示遇到下一个 operator
switch (
operator // operator 指的是上一个 operator,而不是现在的 c
) {
case '+':
stack.push(num);
break;
case '-':
stack.push(-num);
break;
case '*':
stack.push(stack.pop() * num);
break;
case '/':
stack.push(parseInt(stack.pop() / num));
break;
}
num = 0;
operator = c;
}
}
let res = 0;
while (stack.length > 0) {
res += stack.pop();
}
return res;
};

复杂度

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