Framework Thinking - Neetcode 150 - Evaluate Reverse Polish Notation

Here is the problem for Evaluate Reverse Polish Notation.

1. Understand the Problem

You are given a list of strings representing an expression in Reverse Polish Notation, where:

  • Operands (numbers) appear before their operators.

  • Supported operators are: +, -, *, /.

  • Division should truncate toward zero (i.e., int(a / b) in Python works).

  • You need to evaluate the expression and return one integer.

2. Clarify contraints

  1. Can it have negative number ?
  • May include negative numbers (e.g., “-11”).
  1. Is input always valid?
  • Yes, operations are valid and expression reduces to one number.

  • Example 1: [2,”+”]

if len(stack) < 2:
    raise ValueError("Insufficient operands for operator '{}'".format(token))
  • Example 2: [0,2,”/”]
if token == "/" and b == 0:
    raise ZeroDivisionError("Division by zero is not allowed.")
  • Example 3: [2,2,2,2,”+”]
if len(stack) != 1:
    raise ValueError("Invalid expression: too many operands.")
  1. Division behavior?
  • Truncate toward zero.

  • Example 1: -3 / 2 → -1.5 => -1.

  • Example 2: -2/3 => -0.666 => 0.

3. Brainstorm 2-3 solutions

3.1. Brute force - O(N^2) by copy array

  • Idea: when find “+-*/” => calculate nums[i - 2] / nums[i - 1] => append result + nums[i + 1]

  • Note: Idea about in-place and copy string.

tokens = tokens[:i-2] + [str(result)] + tokens[i+1:]
  • In-place: O(1) => address[0] + k * len(size_char)

  • Copy new: O(N)

  • Time: O(N^2) (because copy new array)

  • Space: O(N).

3.2. Doubly Linked List - O(N) in-place

  • Idea: inplace calculate to make it O(N)

  • Time: O(N) - in-place replacement.

  • Space: O(N).

3.3. Recursion

  • Idea: because you traverse all the array O(N).

  • Loop from the end, and calculate backward => Each item 1 return.

=> Always think that we do not have easy 1,1,1,+ near to each other => but must be 1,*,1,2,+.

  • Time: O(N).

  • Space: O(N).

3.4. Stack

  • Idea: similar to recursion but easier to implement.

  • Time: O(N).

  • Space: O(N).

4. Implement solutions

4.1. Brute Force - O(N^2).

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        while len(tokens) > 1:
            for i in range(len(tokens)):
                if tokens[i] in "+-*/":
                    a = int(tokens[i-2])
                    b = int(tokens[i-1])
                    if tokens[i] == '+':
                        result = a + b
                    elif tokens[i] == '-':
                        result = a - b
                    elif tokens[i] == '*':
                        result = a * b
                    elif tokens[i] == '/':
                        result = int(a / b)
                    tokens = tokens[:i-2] + [str(result)] + tokens[i+1:]
                    break
        return int(tokens[0])
  • Time: O(N^2).

  • Space: O(N).

4.2. Doubly Linked List - O(N)

class DoublyLinkedList:
    def __init__(self, val, next=None, prev=None):
        self.val = val
        self.next = next
        self.prev = prev

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        head = DoublyLinkedList(tokens[0])
        curr = head

        for i in range(1, len(tokens)):
            curr.next = DoublyLinkedList(tokens[i], prev=curr)
            curr = curr.next

        while head is not None:
            if head.val in "+-*/":
                l = int(head.prev.prev.val)
                r = int(head.prev.val)
                if head.val == '+':
                    res = l + r
                elif head.val == '-':
                    res = l - r
                elif head.val == '*':
                    res = l * r
                else:
                    res = int(l / r)

                head.val = str(res)
                head.prev = head.prev.prev.prev
                if head.prev is not None:
                    head.prev.next = head

            ans = int(head.val)
            head = head.next

        return ans
  • Time: O(N).

  • Space: O(N).

4.3. Recursion - O(N), each item 1 return.

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        def dfs():
            token = tokens.pop()
            if token not in "+-*/":
                return int(token)

            right = dfs()
            left = dfs()

            if token == '+':
                return left + right
            elif token == '-':
                return left - right
            elif token == '*':
                return left * right
            elif token == '/':
                return int(left / right)

        return dfs()
  • Time: O(N).

  • Space: O(N).

4.4. Stack - O(N), easy implement than recursion

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stack = []
        for c in tokens:
            if c == "+":
                stack.append(stack.pop() + stack.pop())
            elif c == "-":
                a, b = stack.pop(), stack.pop()
                stack.append(b - a)
            elif c == "*":
                stack.append(stack.pop() * stack.pop())
            elif c == "/":
                a, b = stack.pop(), stack.pop()
                stack.append(int(float(b) / a))
            else:
                stack.append(int(c))
        return stack[0]
  • Time: O(N).

  • Space: O(N).

5. Dry run examples

input = ["2","1","+","3","*"]
Token Action Stack
"2" push 2 [2]
"1" push 1 [2, 1]
"+" pop → 2 + 1 = 3 [3]
"3" push 3 [3, 3]
"*" pop → 3 × 3 = 9 [9]
November 25, 2025