Basic Calculator — Solution in Python, Java & C++
Basic Calculator solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. A hard problem on strings and math.
Basic Calculator is a hard coding problem on strings, math and stack, asked in Amazon, Google, Microsoft and Meta interviews.
- Difficulty: Hard
- Topics: Strings, Math, Stack, Recursion
- Asked at: Amazon, Google, Microsoft, Meta, Indeed
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
Evaluate the arithmetic expression s and return its value. Do not use any built-in function that evaluates strings as code.
s contains non-negative integers, the operators + and -, parentheses ( ), and spaces (which mean nothing). - may also be used as a unary minus — at the very start of the expression or right after (, as in -5 or -(2 + 3) — but + is never unary, and two operators never appear next to each other.
Example 1
Input: s = "7 - (3 + 2)"
Output: 2
Example 2
Input: s = "-(4 - 10) + 1"
Output: 7
Explanation: The unary minus negates the whole bracket: -(-6) + 1.
Example 3
Input: s = "(12+(3-(5+1)))-(20)"
Output: -11
Constraints
1 <= s.length <= 3 * 10^5s consists of digits, '+', '-', '(', ')' and ' 's is a valid expressionEvery number and every intermediate result fits in a signed 32-bit integer
Hints for Basic Calculator
Hint 1
Without parentheses the answer is just a running sum: each number is added with the sign in front of it.
Hint 2
A parenthesised group is its own running sum, which is then added to the outer sum with the sign in front of the
(.Hint 3
On
(, push the current result and sign onto a stack and start fresh; on), finish the inner sum and combine:result = savedResult + savedSign * result.
How to solve Basic Calculator
With only + and -, an expression is a signed sum. Parentheses nest sums, so keep a stack of the outer (result, sign) pairs that are waiting for an inner sum to finish.
Approach
- Keep
result = 0,sign = 1,num = 0and an empty stack. Skip spaces. - Digit:
num = num * 10 + digit. +or-: addsign * numtoresult, resetnum, and setsignto+1or-1.(: pushresultandsign, then resetresult = 0,sign = 1.): addsign * numtoresult, resetnum, pop the saved sign and result, and setresult = savedResult + savedSign * result.- At the end return
result + sign * num.
Why it works
Between parentheses the algorithm maintains the invariant value so far = result + sign * num. A ( suspends the outer sum exactly as it stood, including the sign that applies to the whole group, so the inner sum can be computed from scratch and then folded in with that sign. A unary minus needs no special case: at the start of a group result is 0, so -x is evaluated as 0 - x.
Complexity
- Time —
O(n) - Space —
O(n) for the stack of nested groups
Pitfalls
- Numbers have several digits — accumulate them instead of reading one character.
- Flush the pending number before handling
)and at the end of the string. - A unary minus before
(must negate the whole group, which the saved sign handles automatically.
Reference solution
Python
def calculate(s: str) -> int:
result = 0
sign = 1
num = 0
st = []
for c in s:
if c.isdigit():
num = num * 10 + int(c)
elif c == '+' or c == '-':
result += sign * num
num = 0
sign = 1 if c == '+' else -1
elif c == '(':
st.append(result)
st.append(sign)
result = 0
sign = 1
elif c == ')':
result += sign * num
num = 0
saved_sign = st.pop()
saved_result = st.pop()
result = saved_result + saved_sign * result
return result + sign * numJava
public static int calculate(String s) {
long result = 0, num = 0;
int sign = 1;
Deque<Long> st = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= '0' && c <= '9') {
num = num * 10 + (c - '0');
} else if (c == '+' || c == '-') {
result += sign * num;
num = 0;
sign = c == '+' ? 1 : -1;
} else if (c == '(') {
st.push(result);
st.push((long) sign);
result = 0;
sign = 1;
} else if (c == ')') {
result += sign * num;
num = 0;
long savedSign = st.pop();
long savedResult = st.pop();
result = savedResult + savedSign * result;
}
}
return (int) (result + sign * num);
}C++
int calculate(string s) {
long long result = 0, num = 0;
int sign = 1;
vector<long long> st;
for (char c : s) {
if (c >= '0' && c <= '9') {
num = num * 10 + (c - '0');
} else if (c == '+' || c == '-') {
result += sign * num;
num = 0;
sign = c == '+' ? 1 : -1;
} else if (c == '(') {
st.push_back(result);
st.push_back(sign);
result = 0;
sign = 1;
} else if (c == ')') {
result += sign * num;
num = 0;
long long savedSign = st.back(); st.pop_back();
long long savedResult = st.back(); st.pop_back();
result = savedResult + savedSign * result;
}
}
return (int)(result + sign * num);
}JavaScript
var calculate = function(s) {
var result = 0, sign = 1, num = 0, st = [];
for (var i = 0; i < s.length; i++) {
var c = s[i];
if (c >= "0" && c <= "9") {
num = num * 10 + (c.charCodeAt(0) - 48);
} else if (c === "+" || c === "-") {
result += sign * num;
num = 0;
sign = c === "+" ? 1 : -1;
} else if (c === "(") {
st.push(result, sign);
result = 0;
sign = 1;
} else if (c === ")") {
result += sign * num;
num = 0;
var savedSign = st.pop();
var savedResult = st.pop();
result = savedResult + savedSign * result;
}
}
return result + sign * num;
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 515 strings problems · the whole catalogue
Learn the technique: Strings · Stack Data Structure