This isn't a string problem. It's a memory problem — and the way you're forced to remember things points straight at one data structure.
You're handed an expression like 2 3 1 * + 9 -. The operators sit after the
numbers they act on. That's postfix notation. Ordinary math is infix — the operator lives between its operands
(2 + 3). Postfix flips it: 2 3 +.
It looks like text to chew through. It isn't. The string is just how the input is written down. The actual question is quieter and more interesting:
Answer that honestly and the stack falls out on its own. You never have to memorize "postfix → stack" — you can rederive it every time.
In infix, 2 + 3 * 4 needs rules — multiply before add — so it means 2 + (3 * 4) = 14.
Postfix writes the execution order out in the open:
When * appears in 2 3 4 * +, the two numbers waiting right in front of it are
3 and 4. Multiply → 12. The expression is now effectively
2 12 + → 14. No parentheses, no precedence table, no expression tree to build. You
only need to remember unfinished numbers.
Scan 2 3 1 * + 9 - slowly. You read 2, then 3, then 1 —
nothing can happen, so they wait. Then * arrives. Which two numbers does it grab? The two
most recent: 3 and 1. Their result, 3, becomes a fresh number
that might feed a later operator.
"Most recent in, first one out." That phrase is the definition of a stack: Last In, First Out. So the stack isn't just convenient here. It matches the literal shape of the problem.
You add clean plates on top and take from the top. The last plate stacked is the first grabbed. Numbers pile up the same way until an operator "takes" the top two.
Each page you visit is pushed on top of your history. "Back" always returns you to the most recent page first — the same order the stack hands operands to an operator.
Ctrl-Z reverses your latest action, not your first. Unfinished work waits in a pile; the freshest item is resolved first. Postfix operands wait exactly like this.
Walk one token at a time through 2 3 1 * + 9 -. Watch numbers get pushed, and watch each operator
pop the top two and push its result back. Use Next, or hit Play to autorun.
Notice the last subtraction: the stack holds
[5, 9], but the answer is 5 − 9 = −4, not 9 − 5. That ordering trap is the single
most common bug — the next section is entirely about it.
For 5 9 - the operation is 5 - 9. But when you pop, the top of the stack comes off
first — and the top is 9. So the first pop is the right operand, the second pop is
the left one.
int a = stack.pop(); // 9 int b = stack.pop(); // 5 int r = a - b; // 4 ✗
int right = stack.pop(); // 9 int left = stack.pop(); // 5 int r = left - right; // -4 ✓
right and left — never a and b.
Directional names make it almost impossible to reverse subtraction or division.
Once the reasoning is right, the code reads almost like English. For every token: if it's a number, push it. If it's an operator, pop two, apply, push the result. When you're done, the one value left on the stack is the answer.
# create an empty stack for each token: if token is a number: push(token) else: # it's an operator right = pop() left = pop() push( left op right ) return pop() # the final answer
Every completed operation produces a new operand, which is why you push the result back. In
2 3 + 4 *, the 2 3 + becomes 5, and that 5 is exactly what
4 * needs next.
When a stack solution misbehaves, don't stare at the code — build a table. Track the token, the action, and the stack state after it. The bug usually jumps out.
| Token | Action | Stack after |
|---|---|---|
| 2 | push 2 | [2] |
| 3 | push 3 | [2, 3] |
| 1 | push 1 | [2, 3, 1] |
| * | 3 × 1 = 3 | [2, 3] |
| + | 2 + 3 = 5 | [5] |
| 9 | push 9 | [5, 9] |
| − | 5 − 9 = −4 | [−4] |
2 5 - is -3. Keep signed integers —
plain int handles it.
Each number pushes one value (+1). Each binary operator pops two and pushes one (net −1). A valid postfix expression has exactly one more operand than operators, so the stack collapses to a single value:
For 2 3 1 * + 9 -: four operands (2, 3, 1, 9), three operators (*, +, −). Since 4 = 3 + 1, it's
valid — and it must end with one number. The deeper reason is an invariant: at any point, the
stack holds exactly the fully-evaluated sub-results that no later operator has consumed yet.
The expression 2 3 4 * + means 2 + (3 * 4). Draw it as a tree and read it in
postorder — left child, right child, then the node — and you get the postfix string back.
That's literally why it's called "post"-fix: the operator prints after its operands.
postorder: 2 → 3 → 4 → * → + = 2 3 4 * +
Same expression, 2 + (3 * 4), written three ways. The only thing that moves is the operator's
position relative to its operands.
1 2 3 4 5 + + + +.
You have to at least look at every token, so O(n) time is optimal. A naive approach — repeatedly scanning a list for the next operator and rewriting it in place — also works but wastes effort re-searching. The stack's insight is that the operands you need are always already on top, so no searching is required.
Tokens are space-separated and numbers can be multi-digit. Split on spaces ("12 35 +" →
12, 35), don't iterate characters.
First pop = right operand, second = left. Compute left − right, never the other way.
Every operation's output is a future operand. Forget to push it and the next operator starves.
Postfix already encodes order. Don't reach for "* before +" — just process each operator when you meet it.
Prefer Deque<Integer> backed by ArrayDeque over the legacy Stack
class. The switch reads naturally: a token is either one of three operators, or (default) a number.
import java.util.*; public class Main { static int apply(int left, int right, String op) { switch (op) { case "+": return left + right; case "-": return left - right; case "*": return left * right; default: throw new IllegalArgumentException(op); } } static int evaluate(String expr) { Deque<Integer> stack = new ArrayDeque<>(); for (String t : expr.split(" ")) { if (t.equals("+") || t.equals("-") || t.equals("*")) { int right = stack.pop(); // first pop = right int left = stack.pop(); // second pop = left stack.push(apply(left, right, t)); } else { stack.push(Integer.parseInt(t)); } } return stack.pop(); } public static void main(String[] args) { System.out.println(evaluate("2 3 1 * + 9 -")); // -4 } }
left op right, push the result.