Evaluate Reverse Polish Notation is the classic stack problem. It looks intimidating, but a stack turns it into a clean one-pass scan — and it teaches you exactly when a stack is the right tool.
Problem. You are given an array of tokens that represents an arithmetic expression in Reverse
Polish Notation (RPN, or postfix). Each token is either an integer or one of the operators +, -,
*, /. Evaluate the expression and return the integer result. Division truncates toward zero.
Example: tokens = ["2", "1", "+", "3", "*"] → 9. It means (2 + 1) * 3 = 9. In RPN the operator
comes after its two operands, so there are no parentheses at all.
The slow way first
You might try to convert the RPN back to normal infix notation, add parentheses, then evaluate that — or write a recursive parser. Both are fiddly and easy to get wrong: you have to track operator precedence and matching brackets. That is a lot of machinery for what turns out to be a very simple scan.
The question to ask: when I read an operator, where are its two operands? In RPN they are always the two most recent numbers that have not yet been used. "Most recent, not yet used" is the exact description of a stack.
The idea: push numbers, pop on an operator
Keep a stack. Scan the tokens left to right:
- If the token is a number, push it.
- If the token is an operator, pop the top two values (
bfirst, thena), computea op b, and push the result back.
When the scan ends, the stack holds exactly one value — the answer.
The key insight: an operator always combines the two newest numbers. Because a stack gives you those instantly with two pops, the whole evaluation is one linear pass with no parsing.
Walk through it
Step through the animation. The tok pointer scans the tokens; the stack grows upward on the right. We push 2, then 1. At + we pop 1 and 2, push 3. We push 3, giving [3, 3]. At * we pop 3 and 3, push 9. One value remains — the answer is 9.
Pseudocode
stack = empty
for each token:
if token is a number:
push int(token)
else: # token is an operator
b = pop() # second operand (popped first!)
a = pop() # first operand
push a (op) b # apply and push the result
return the single value left on the stackThe Python solution
def eval_rpn(tokens):
ops = {"+": add, "-": sub, "*": mul, "/": truediv}
stack = []
for tok in tokens:
if tok not in ops:
stack.append(int(tok))
else:
b = stack.pop()
a = stack.pop()
res = ops[tok](a, b)
stack.append(int(res))
return stack[0]opsmaps each operator string to a function (from operator import add, sub, mul, truediv). It avoids a longif/elifchain.- A token is a number whenever it is not in
ops, soint(tok)is safe (this handles negatives like"-4"correctly). - Order matters: we pop
bfirst, thena, and computea op b. For-and/the operands are not interchangeable, so getting this backwards breaks those cases. int(res)truncates the division result toward zero, matching the problem rule.- After the loop the stack has exactly one element, so
stack[0]is the answer.
Complexity
| Case | Time | Notes |
|---|---|---|
| Scan every token once | O(n) (moderate) | each push/pop is O(1) |
O(n) (moderate)We touch each token once and every stack operation is constant time, so the whole thing is O(n) time. The stack can hold up to about half the tokens at once, so it uses O(n) extra space.
When this pattern shows up
When a problem needs the most recent unmatched thing — matching brackets, nested structures, undo history, "next greater element," or evaluating postfix/prefix expressions — reach for a stack. RPN evaluation is the cleanest example: the operator always wants the two newest operands.
Mind the pop order for non-commutative operators. You pop b first and a second, so you must compute
a op b, not b op a. For ["6", "2", "/"] the answer is 6 / 2 = 3, not 2 / 6 — popping in the
wrong order silently gives the wrong result.
Practice
Evaluate tokens = ['4', '13', '5', '/', '+'] by hand. What is on the stack right after the '/' token, and what is the final answer?
1. Why is a stack the natural data structure for evaluating RPN?
2. When you hit an operator, in what order do the popped values combine?
3. What is the time complexity of this solution?
4. After scanning all tokens of a valid RPN expression, what is on the stack?