# 224. Basic Calculator
Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .
Example 1:
Input: "1 + 1"
Output: 2
Example 2:
Input: " 2-1 + 2 "
Output: 3
Example 3:
Input: "(1+(4+5+2)-3)+(6+8)"
Output: 23
Note:
- You may assume that the given expression is always valid.
- Do not use the eval built-in library function.
# Solution
Approach 1: Stack for everything.
Approach 2: Stack for signs.
Approach 3: general solution is to build postfix notation and evaluate.
# Code (Python)
Approach 1:
import re
class Solution:
def calculate(self, expr: str) -> int:
# trick: wrap the original expression with a bracket to cut corner cases
tokens = ['('] + self._tokenize(expr) + [')']
if not tokens:
return 0
stack = []
for token in tokens:
if token != ')':
stack.append(token)
else:
temp_result = 0
while len(stack) and stack[-1] != '(':
num = int(stack.pop())
op = stack.pop()
if op == '(':
temp_result += num
stack.append(temp_result)
break
else:
temp_result += num if op == '+' else -num
# this handles cases like 1-(-2)
if stack[-1] == '(':
stack.pop()
stack.append(temp_result)
return stack[0]
def _tokenize(self, expression):
return [e for e in re.split('(\D)', expression) if e and not re.match('\s', e)]
Approach 3:
class Solution:
def calculate(self, s: str) -> int:
# http://bookshadow.com/weblog/2015/06/09/leetcode-basic-calculator/
# idea for all calculators: convert to postfix notation, then evalutate
# example of postfix: (a+b)*c - (a+b)/d => [a, b, +, c, *, a, b, + d, /, -]
# this following solution work for all operators in +-*/
return self._evaluate(self._to_postfix(s))
def _to_postfix(self, expression):
# two stacks: a stack (list) storing postfix, and an operator stack to store operators and left paren
# operators have priorities: +- has priority 1, */ has priority 2
postfix = []
operators = []
value = '' # to handle multiple digits
ops = {
'+': 1,
'-': 1,
'*': 2,
'/': 2
}
for char in expression:
if not char or char == ' ':
continue
if char.isdigit():
value += char
else:
if value:
postfix.append(int(value))
value = ''
if char == '(':
operators.append(char)
elif char in ops:
# pop from operators with higher or equal priority, or until meet a (, then push char onto operators
while operators and operators[-1] != '(' and ops[operators[-1]] >= ops[char]:
postfix.append(operators.pop())
operators.append(char)
else: # )
# pop from operators until meet a (
while operators and operators[-1] != '(':
postfix.append(operators.pop())
operators.pop()
# pop remaining digits first
if value:
postfix.append(int(value))
# pop remaining operators
while operators:
postfix.append(operators.pop())
return postfix
def _evaluate(self, postfix):
ops = {
'+': lambda a, b: a + b,
'-': lambda a, b: a - b,
'*': lambda a, b: a * b,
'/': lambda a, b: a / b
}
current = []
for item in postfix:
if item in ops:
val2, val1 = current.pop(), current.pop()
current.append(ops[item](val1, val2))
else:
current.append(item)
return current[0]
# Code (C++)
Approach 1:
// Stack for everything.
class Solution {
public:
int calculate(string s) {
stack<string> st;
st.push("(");
int head = 0;
for (int i = 0; i <= s.size(); ++i)
{
if (i == s.size() || !isdigit(s[i]))
{
if (i > head)
{
st.push(s.substr(head, i - head));
}
if (i == s.size() || s[i] == ')')
{
int total = stoi(st.top());
st.pop();
if (st.top() == "-")
total = 0 - total;
while (!st.empty() && st.top() != "(")
{
st.pop(); // pop "+" or "-".
int num = stoi(st.top());
st.pop();
if (st.top() == "-")
num = 0 - num;
total += num;
}
st.pop(); // pop "(".
st.push(std::to_string(total));
}
else if (i < s.size() && s[i] != ' ')
{
st.push(string(1, s[i]));
}
head = i + 1;
}
}
return stoi(st.top());
}
};
Approach 2:
// Stack for signs.
class Solution {
public:
int calculate(string s) {
stack<int> stSign;
stSign.push(1);
int res = 0;
int sign = 1;
int head = 0;
for (int i = 0; i <= s.size(); ++i)
{
if (i == s.size() || !isdigit(s[i]))
{
if (i > head)
{
res += sign * stoi(s.substr(head, i - head));
}
if (i < s.size())
{
if (s[i] == '+')
sign = stSign.top();
else if (s[i] == '-')
sign = 0 - stSign.top();
else if (s[i] == '(')
stSign.push(sign);
else if (s[i] == ')')
stSign.pop();
}
head = i + 1;
}
}
return res;
}
};