How to Explain Evaluate Reverse Polish Notation in a Coding Interview (Step-by-Step)

How to Explain Evaluate Reverse Polish Notation in a Coding Interview (Step-by-Step)

Reverse Polish Notation is the stack problem that proves you understand why stacks exist — not just how to use them. The algorithm is elegant and short. What trips candidates up is the operand-order subtlety on subtraction and division, and the integer truncation rule that Python gets wrong by default.

In this post, you’ll learn how to walk an interviewer through LeetCode 150 with confidence: what RPN is and why a stack solves it naturally, the pop-order gotcha, the truncation-toward-zero detail, a full token-by-token stack trace, and every edge case worth calling out.


Problem Statement

LeetCode 150 Medium

You are given an array of strings tokens that represent an arithmetic expression in Reverse Polish Notation. Evaluate the expression and return an integer representing the result.

Note: The valid operators are '+', '-', '*', and '/'. Each operand may be an integer or another expression. Division between two integers always truncates toward zero. The input is guaranteed to be a valid RPN expression and will always produce a result that fits in a 32-bit integer.

Examples

Example 1
Input: tokens = [“2″,”1″,”+”,”3″,”*”]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Example 2
Input: tokens = [“4″,”13″,”5″,”/”,”+”]
Output: 6
Explanation: (4 + (13 / 5)) = (4 + 2) = 6
Example 3
Input: tokens = [“10″,”6″,”9″,”3″,”+”,”-11″,”*”,”/”,”*”,”17″,”+”,”5″,”+”]
Output: 22

Constraints

  • 1 <= tokens.length <= 104
  • tokens[i] is either an operator or an integer in the range [-200, 200]
  • The expression is always valid — no division by zero

What Is Reverse Polish Notation?

Infix (what we write)
(2 + 1) * 3
Operator sits between operands. Requires parentheses and precedence rules to parse.
Postfix / RPN (what we’re given)
2 1 + 3 *
Operator comes after its operands. No parentheses needed — precedence is implicit in order.
“RPN eliminates the need for parentheses entirely. Each operator always applies to the two most recently seen operands — which is exactly what a stack gives us. The top two items on the stack are always the operands for the next operator.”

The Key Insight — Operators Always Act on the Top Two

💡 Core Insight

Scan tokens left to right. If a token is a number, push it. If it is an operator, pop the top two numbers, apply the operation, and push the result back. Because operators always consume exactly the two most recent values, the stack keeps the evaluation order correct automatically.

At the end of a valid expression, exactly one value remains on the stack — the final answer.

“The reason a stack is the natural structure here is that evaluation in RPN is last-in-first-out: the most recently pushed operands are the ones consumed by the next operator. A stack encodes that ordering for free.”

The Four Operators — and the Pop-Order Gotcha

+
b + a
(order doesn’t matter)
b − a
⚠ pop a first, then b
×
b × a
(order doesn’t matter)
÷
b ÷ a
⚠ pop a first, then b
“When we pop two values, the first pop gives the right operand and the second pop gives the left operand. For addition and multiplication this doesn’t matter — they’re commutative. For subtraction and division it matters enormously. If I pop a then b, the correct operation is b - a and b / a — not the other way around.”

Step 2: Explain the Algorithm in Plain English

1 Initialise an empty stack

The stack will hold integer operands as we encounter them. All values on the stack are numbers — never operators.

2 Iterate through each token

For each token: if it is not one of the four operators, it must be an integer — convert it with int() and push it onto the stack.

3 On an operator — pop, compute, push

Pop a (right operand) then b (left operand). Apply the operator: b + a, b - a, b * a, or int(b / a). Push the integer result back onto the stack.

4 Return the single remaining value

After all tokens are processed, the stack contains exactly one element — the final evaluated result. Return stack[0] or stack.pop().


Stack Trace Visualised — [“2″,”1″,”+”,”3″,”*”]

Expected result: ((2 + 1) * 3) = 9. Tracing every token step by step.

“2”
Number token → convert to int → push 2
Stack: [2]
Stack
2
“1”
Number token → convert to int → push 1
Stack: [2, 1]
Stack
1
2
“+”
Operator → pop a=1, pop b=2 → compute b+a = 2+1 = 3 → push 3
Stack: [3]
Stack
3
“3”
Number token → convert to int → push 3
Stack: [3, 3]
Stack
3
3
“*”
Operator → pop a=3, pop b=3 → compute b*a = 3*3 = 9 → push 9
Stack: [9]
Stack
9
✓ All tokens processed — stack has one element
Return stack.pop() → 9

The Truncation Gotcha — Python Division vs. the Problem’s Rule

⚠️ Python’s // operator truncates toward negative infinity — not toward zero

The problem requires truncation toward zero (C-style integer division). For positive numbers these are identical. For negative numbers they differ:

Negative example
−7 ÷ 2
Python −7 // 2 = −4  ✗
Expected: −3  ✓
The fix
int(b / a)
int(−7 / 2) = int(−3.5) = −3  ✓
int() truncates toward zero in Python
“This is the subtlest part of the problem. Using b // a in Python would give the wrong answer for any division that produces a negative non-integer result. int(b / a) uses Python’s float division first, then int() which truncates toward zero — matching the problem’s spec exactly.”

Step 3: Talk Through the Code

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stack = []
        operators = {'+', '-', '*', '/'}

        for token in tokens:
            if token not in operators:
                stack.append(int(token))   # Convert string to int and push
            else:
                a = stack.pop()            # Right operand (most recently pushed)
                b = stack.pop()            # Left operand

                if token == '+':
                    stack.append(b + a)
                elif token == '-':
                    stack.append(b - a)    # b - a, NOT a - b
                elif token == '*':
                    stack.append(b * a)
                elif token == '/':
                    stack.append(int(b / a))  # Truncate toward zero, not //

        return stack[0]

Point out the operator set check token not in operators — it’s cleaner than token.lstrip('-').isdigit() because it handles negative number tokens like "-11" correctly without any string manipulation. Negative numbers are valid tokens and will fail the operator check, routing them correctly to int(token).


Step 4: Highlight Edge Cases

1 Single token — [“42”]
“A single number with no operators. It’s pushed once and never popped. We return stack[0] which is 42. Correct — the problem guarantees a valid expression and a single number is a valid one.”
2 Negative number tokens — [“-11”]
“Tokens like '-11' start with a dash and might look like operators. The operator check token not in {'+','-','*','/'} correctly identifies '-11' as a non-operator, and int('-11') converts it cleanly to -11.”
3 Division truncation with negatives — [“7″,”2″,”/”] vs [“-7″,”2″,”/”]
7 / 2 = 3 (both approaches agree). -7 / 2 should be -3 by truncation toward zero — int(-7/2) gives -3, while -7 // 2 gives -4. The distinction only matters for negative non-integer results.”
4 Operand order on subtraction — [“5″,”3″,”-“]
“We pop a = 3 first (top of stack), then b = 5. The result is b - a = 5 - 3 = 2, not a - b = 3 - 5 = -2. Getting the pop order backwards on subtraction is the most common coding mistake on this problem.”
5 Deeply nested expressions
“Example 3 in the problem has 13 tokens with multiple nested operations. The algorithm handles arbitrary depth transparently — intermediate results are just more integers on the stack, indistinguishable from original operands.”

Step 5: State Time and Space Complexity

DimensionComplexityReason
Time O(n) Each token is visited exactly once; each push and pop is O(1)
Space O(n) In the worst case — all operands before any operator — the stack holds up to n/2 elements
“Time is O(n) — one pass through the token array, one O(1) operation per token. Space is O(n) in the worst case: an expression like ['1','2','3','4','+','+','+'] pushes all operands before any operator fires. The stack can hold at most n/2 elements at peak for a fully balanced expression, but we still call it O(n).”

Interview Checklist for Evaluate Reverse Polish Notation

  • Explain what RPN is — operator comes after its operands, no parentheses needed
  • Name the LIFO property — the most recent two values are always the next operands
  • State the algorithm: numbers push, operators pop-compute-push
  • Explicitly call out the pop order — first pop is right operand, second is left
  • Show why this matters: subtraction and division are non-commutative
  • Call out the truncation-toward-zero rule — and why Python’s // is wrong for negatives
  • Use int(b / a) not b // a for division
  • Use token not in operators to cleanly handle negative number tokens like "-11"
  • Call out: single token → push and return; deeply nested → handled transparently
  • State O(n) time and O(n) space

If you can solve Evaluate Reverse Polish Notation cleanly, try these next:

💡 The most common mistake in this problem is getting the subtraction or division operand order backwards — writing a - b instead of b - a. Before finishing, trace through ["5","3","-"] mentally: pop a=3, pop b=5, result is 5-3=2. If your code gives -2, the order is flipped.
Scroll to Top