Basic Calculator asks you to evaluate a string like "1+(2-3)" by hand — no eval. It is the classic test of whether you can use a stack to handle nesting, the same skill behind matching brackets and parsing.
Problem. Given a string s representing a valid expression of digits, +, -, spaces, and
parentheses, return its integer value. There is no multiplication or division — only addition,
subtraction, and nesting.
Example: s = "1+(2-3)" → 0 (because 2 - 3 = -1, then 1 + (-1) = 0).
The slow way first
You might reach for recursion: every time you hit (, recurse on the inner string and splice the value back in. That works, but finding the matching ) for each ( means re-scanning, and the bookkeeping for where each sub-string starts and ends gets fiddly fast.
The question to ask: when I dive into a parenthesis, what do I need to come back to? I need the result I had built so far and the sign that sits in front of the parenthesis. That is exactly two values — perfect for a stack.
The idea: a running result, a sign, and a stack
Scan the string once. Keep a running result, a current sign (+1 or -1), and a number being built. For each character:
- a digit extends the current number;
+or-flushes the number intoresultand setssign;(pushes the currentresultandsignonto the stack, then resets them for the inner expression;)pops the saved sign and result back and folds the inner value in:result = saved_res + saved_sign * result.
The key insight: the stack lets each level of nesting remember the context it left behind, so when the parenthesis closes we resume exactly where we paused.
Walk through it
Step through the animation. The scan pointer moves over "1+(2-3)". At ( we push (1, +1) and reset to 0; inside we compute 2 - 3 = -1; at ) we pop and fold: 1 + (+1)·(-1) = 0.
Pseudocode
result = 0, sign = +1, num = 0, empty stack
for each char ch in s:
if ch is a digit:
num = num * 10 + ch # build multi-digit numbers
else:
if num: result += sign * num # flush the pending number
if ch is '+': sign = +1
if ch is '-': sign = -1
if ch is '(': # save the outside, start fresh
push result, push sign
result = 0, sign = +1
if ch is ')': # restore and fold inner value in
saved_sign = pop, saved_res = pop
result = saved_res + saved_sign * result
return result + sign * num # flush any trailing numberThe Python solution
def calculate(s):
result = 0
sign = 1
num = 0
stack = []
for ch in s:
if ch.isdigit():
num = num * 10 + int(ch)
else:
if num:
result += sign * num
num = 0
if ch == '+':
sign = 1
elif ch == '-':
sign = -1
elif ch == '(':
stack.append(result)
stack.append(sign)
result, sign = 0, 1
elif ch == ')':
saved_sign = stack.pop()
saved_res = stack.pop()
result = saved_res + saved_sign * result
return result + sign * numresultis the value accumulated at the current nesting level;signis what to multiply the next number by.numbuilds multi-digit numbers —num * 10 + int(ch)shifts left and adds the new digit.- On any non-digit we first flush the pending
numintoresult, then act on the character. - On
(we pushresultandsign, then reset — the inner expression starts clean. - On
)we pop the saved sign and result and combine them:saved_res + saved_sign * result. - The final
returnflushes any number still being built (spaces and the loop end leave it pending).
Complexity
| Case | Time | Notes |
|---|---|---|
| Single scan | O(n) (moderate) | each char handled once |
| Stack pushes/pops | O(n) (moderate) | at most one per parenthesis |
O(n) (moderate)We pass over the string once. The stack can hold up to O(n) values when the expression is deeply nested, so extra space is O(n).
When this pattern shows up
Whenever a problem has nesting — parentheses, brackets, nested encodings like "3[a2[c]]" — think
stack. Push the context you are leaving, do the inner work, then pop to resume. Basic Calculator,
Decode String, and Valid Parentheses are all the same move.
Do not forget the trailing flush. The last number in the string has no operator after it to trigger
the flush inside the loop, so you must add sign * num once more after the loop ends.
Practice
While scanning '1+(2-3)', what two values get pushed onto the stack when we reach the '(' character?
1. What two values do we push onto the stack when we see a '(' ?
2. When we reach ')', how do we combine the inner result with the saved values?
3. Why do we add sign * num once more after the loop ends?
4. What is the worst-case extra space for this solution?