AlgoMaster Logo

Evaluate Reverse Polish Notation

Last Updated: March 29, 2026

medium
4 min read

Understanding the Problem

We are given a mathematical expression, but not in the usual infix notation like (2 + 1) * 3. Instead, it is written in Reverse Polish Notation (RPN), also called postfix notation. In RPN, the operator comes after its two operands. So 2 + 1 becomes 2 1 +, and (2 + 1) * 3 becomes 2 1 + 3 *.

The beauty of RPN is that it does not need parentheses. The order of operations is completely determined by the position of operators relative to operands. Every time we encounter an operator, we know it applies to the two most recent operands. This "last in, first out" behavior points directly to a stack.

Key Constraints:

  • 1 <= tokens.length <= 10^4 → With up to 10,000 tokens, we need O(n) or O(n log n). A single-pass O(n) stack approach is ideal.
  • Values in the range [-200, 200] → Intermediate results fit in a 32-bit integer (the problem guarantees this), so no overflow handling needed.
  • Division truncates toward zero → In most languages, integer division already truncates toward zero, but in Python, the // operator floors toward negative infinity. We need int(a / b) instead.
  • Input is always valid → We do not need to handle malformed expressions or mismatched operator/operand counts.

Approach 1: Stack-Based Evaluation

Intuition

Think about how RPN works. Consider the expression ["2","1","+","3","*"], which represents (2 + 1) * 3. As we scan from left to right:

  • We see 2, then 1. These are just numbers, so we remember them.
  • We see +. This means "add the last two numbers." That gives us 2 + 1 = 3. Now we forget about 2 and 1 individually, and just remember 3.
  • We see 3. Another number. We remember it alongside our running result of 3.
  • We see *. Multiply the last two numbers: 3 * 3 = 9. That is our answer.

Notice the pattern: numbers pile up, and operators consume the top two. This is exactly what a stack does. Numbers get pushed, operators pop two values, compute a result, and push it back. At the end, the stack has exactly one element: the final answer.

The only subtlety is operand order. When we pop two values for subtraction or division, the first popped value is the right operand and the second popped value is the left operand. If the expression is 5 3 -, we want 5 - 3 = 2, not 3 - 5 = -2. Since 3 was pushed last, it gets popped first, so we need: secondPopped - firstPopped.

Algorithm

  1. Initialize an empty stack.
  2. Iterate through each token in the input array.
  3. If the token is an operator (+, -, *, /), pop the top two elements from the stack. Call them b (first pop, right operand) and a (second pop, left operand).
  4. Apply the operator: compute a op b.
  5. Push the result back onto the stack.
  6. If the token is a number, parse it and push it onto the stack.
  7. After processing all tokens, the stack contains exactly one element. Return it.

Example Walkthrough

1Start: push numbers onto the stack as we scan left to right
0
10
i
1
6
2
9
3
3
4
+
5
-11
6
*
7
/
8
*
9
17
10
+
11
5
12
+
1/7
1Stack is empty, ready to process tokens
1/7

Code

The stack approach is already optimal at O(n) time. But what if we want to avoid the overhead of a stack class? We can simulate the stack with a plain array and a pointer.

Approach 2: Array-Based In-Place Evaluation

Intuition

The stack approach works great, but we can be a bit cleverer about memory. Instead of creating a separate stack, we can use a pointer into an integer array. Since each operator consumes two operands and produces one, the "active" portion of our working space only ever grows by one (for a number) or shrinks by one (for an operator). We can simulate the stack using an array and a top-of-stack index.

This is functionally identical to Approach 1. The difference is purely mechanical: we manage the stack ourselves with an array and an index pointer instead of relying on a stack class. This can be marginally faster in practice because raw array access avoids method call overhead.

Algorithm

  1. Create an integer array of size (tokens.length + 1) / 2 (the maximum number of operands).
  2. Maintain a top pointer starting at -1.
  3. For each token:
    • If it is an operator, compute arr[top-1] op arr[top], store the result in arr[top-1], and decrement top.
    • If it is a number, increment top and store the parsed value at arr[top].
  4. Return arr[0] (the single remaining element).

Example Walkthrough

1Initialize: arr is empty, top=-1
0
_
1
_
2
_
1/6

Code