Skip to content
dsa450for five year olds

Stacks & Queues · 12 of 38

Evaluation of Postfix expression

Work out a math sentence where each sign comes after its two numbers, by keeping the numbers in a pile and combining the top two whenever a sign shows up.

Simple way
time O(n^2)
room O(n)
Clever way
time O(n)
room O(n)

The problem, simply

In a postfix sentence, each sign comes right after the two things it works on. So 3 4 + means 3 + 4, and 5 1 2 + 4 * + 3 - means 5 + (1 + 2) * 4 - 3.

You get the pieces as a list of strings, numbers and the signs + - * /. Work out the value. Division keeps only the whole part, cutting toward zero. You may assume the sentence is valid.

The nice thing about postfix: there are no brackets and no "times before plus" rules. The order of the pieces already says everything.

A story to remember it

Picture it

array
012345678512+4*+3-i
stack
512top

The pieces of 5 1 2 + 4 * + 3 -. When the first + arrives, the pile holds 5, 1, 2. The + takes the top two, 1 and 2.

  • looking now
  • checking
  • done

Examples

A normal case

In
['2', '3', '1', '*', '+', '9', '-']
Out
-4

3 * 1 is 3, then 2 + 3 is 5, then 5 - 9 is -4.

Big numbers

In
['100', '200', '+', '2', '/', '5', '*', '7', '+']
Out
757

300 / 2 is 150, times 5 is 750, plus 7 is 757. Numbers can have many digits, so do not read them one character at a time.

Order inside a sign

In
['4', '13', '5', '/', '+']
Out
6

13 / 5 is 2, not 5 / 13. The number pushed first is on the left. Then 4 + 2 is 6.

A negative number

In
['-3', '4', '*']
Out
-12

'-3' is a number, not a minus sign. Only a piece that is exactly '-' is a sign.

Only one number

In
['7']
Out
7

No signs at all. The pile ends with 7.

Way 1: the simple way

Keep the pieces in a list. Find the first sign. The two pieces right before it are its numbers. Replace those three pieces with the result. Repeat until one piece is left.

  1. Find the first index k where the piece is a sign.
  2. Work out list[k - 2] op list[k - 1].
  3. Remove the three pieces and put the result at k - 2.
arraybefore
012345678512+4*+3-
arrayafter
0123456534*+3-

One round of Way 1. The first sign is +, at index 3. The pieces 1, 2, + become a single 3, and the list gets shorter by two.

  • looking now
  • checking
  • just added
java
class Solution {
    public int evalRPN(String[] tokens) {
        List<String> list = new ArrayList<>(Arrays.asList(tokens));
        while (list.size() > 1) {
            int k = 0;
            while (!isSign(list.get(k))) k++;                // first sign
            int a = Integer.parseInt(list.get(k - 2));
            int b = Integer.parseInt(list.get(k - 1));
            int r = apply(a, b, list.get(k));
            list.remove(k);                                  // remove the sign
            list.remove(k - 1);                              // and b
            list.set(k - 2, String.valueOf(r));              // a becomes the result
        }
        return Integer.parseInt(list.get(0));
    }

    private boolean isSign(String t) {
        return t.equals("+") || t.equals("-") || t.equals("*") || t.equals("/");
    }

    private int apply(int a, int b, String op) {
        switch (op) {
            case "+": return a + b;
            case "-": return a - b;
            case "*": return a * b;
            default:  return a / b;
        }
    }
}

How long it takes: each round searches the list and removes from the middle, which costs O(n). There can be n / 2 rounds, so O(n^2). Extra room: the list copy, O(n).

Way 2: the clever way

Keep a pile of numbers, a stack.

  1. Read the pieces left to right.
  2. A number: push it.
  3. A sign: pop b, then pop a. Push a op b.
  4. At the end, the pile holds one number. Return it.

Why does this work? In postfix, the two things a sign needs are always the two most recent results. The top of a stack is exactly "most recent".

Working out 5 1 2 + 4 * + 3 - with one pile

01 / 10

array
012345678512+4*+3-i
stack
empty

Start with an empty pile.

  • looking now
  • checking
  • done
  • answer
  • just added
java
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> pile = new ArrayDeque<>();
        for (String t : tokens) {
            switch (t) {
                case "+": pile.push(pile.pop() + pile.pop()); break;
                case "*": pile.push(pile.pop() * pile.pop()); break;
                case "-": {
                    int b = pile.pop(), a = pile.pop();   // b is on top
                    pile.push(a - b);
                    break;
                }
                case "/": {
                    int b = pile.pop(), a = pile.pop();
                    pile.push(a / b);
                    break;
                }
                default: pile.push(Integer.parseInt(t));  // a number, maybe negative
            }
        }
        return pile.pop();
    }
}

How long it takes: one push or two pops and a push per piece, O(n). Extra room: the pile holds at most about n / 2 numbers, O(n).

Watch out for

  • A piece like "-3" is a number. Compare the whole piece with "-", not its first character.
  • Read multi-digit numbers whole. If the input is a single string, split on spaces first.
  • Division by zero is not possible in valid input, but say how you would handle it.
  • If the pile has more than one number at the end, or too few when a sign arrives, the input was not valid postfix.

What interviewers ask next

  • Evaluate prefix instead, like - + 5 * + 1 2 4 3. Read right to left with the same pile, and now the first pop is a and the second is b.
  • Turn a normal sentence into postfix. Use a pile of signs: write numbers out right away, and before pushing a sign, write out every sign on top that is at least as strong. This is the shunting yard method.
  • Build the expression tree. Push leaf nodes for numbers. For a sign, pop two nodes and make them its children.
  • Why do calculators and the Java virtual machine like postfix? No brackets and no precedence rules, so a simple stack machine can run it in one pass.
  • Can you do it without a stack? Use recursion from the end of the list: the last piece is the root sign, and its right and left parts come before it. It still uses the call stack.

Remember this

Grown-up words: the snack pile is a stack, the sentence with signs after their numbers is postfix or Reverse Polish Notation, the two numbers a sign uses are its operands, and turning normal math into postfix is the shunting yard algorithm.