Skip to content

Beginner: foundations · Stacks, queues and linked lists · topic 16 of 61 · 35 min

Stacks

Explanation

A stack adds and removes items at one end, the top: the last item in is the first one out (LIFO). With a Python list, push (append), pop and peek (stack[-1]) are all O(1). Stacks check matching brackets, evaluate postfix expressions, power undo and the back button, and a min-stack can report its smallest item in O(1).

Last in, first out

A stack is a collection where you add and remove items at the same end, called the top. The last item pushed is the first one popped: last in, first out, or LIFO. You cannot reach an item in the middle without first removing everything above it.

Think of it like this: A pile of plates at a wedding buffet: clean plates go on top, and guests take from the top. Your browser's back button works the same way: every page you open is pushed, and Back pops the latest one. Undo in an editor pops your most recent change.

Operations and their cost

OperationPython listCost
push xstack.append(x)O(1) amortised
pop (remove and return the top)stack.pop()O(1)
peek (look at the top)stack[-1]O(1)
is it empty?not stackO(1)
sizelen(stack)O(1)

A Python list works as a stack because append and pop work at the end, where nothing has to shift. pop() on an empty list raises IndexError: pop from empty list, and stack[-1] on an empty list raises IndexError too, so check if stack: first. In JavaScript use an array with push and pop, and arr[arr.length - 1] to peek.

Every running program also has a stack: the call stack remembers which function called which, and each recursive call pushes a new frame. You will lean on that in Module 5.

Valid brackets

A string of brackets is valid when every opening bracket is closed by the same kind of bracket, in the right order: "([]{})" is valid, "([)]" is not. The most recent unclosed bracket must be closed first, which is exactly LIFO. Push every opening bracket. On a closing bracket, the top of the stack must be its partner, so pop and compare. At the end the stack must be empty, or some bracket was never closed. O(n) time, and O(n) space in the worst case, such as "((((".

python
def is_valid(s):
    pairs = {")": "(", "]": "[", "}": "{"}
    stack = []
    for c in s:
        if c in "([{":
            stack.append(c)
        elif c in pairs:
            if not stack or stack.pop() != pairs[c]:
                return False
    return not stack

print(is_valid("{[()]}"), is_valid("([)]"), is_valid("(("))   # Output: True False False

Postfix (Reverse Polish) expressions

We usually write 3 + 4 × 2 with the operator between the numbers (infix), which needs precedence rules and brackets. In postfix, also called Reverse Polish Notation (RPN), each operator comes after its two operands: "3 4 2 * +" means 3 + (4 × 2) = 11. No brackets or precedence rules are needed, and a stack evaluates it in one pass: push numbers; on an operator, pop two numbers, apply the operator, and push the result.

TokenActionStack after
3push[3]
4push[3, 4]
2push[3, 4, 2]
*pop 2 and 4, push 4 × 2[3, 8]
+pop 8 and 3, push 3 + 8[11]

Order matters for − and ÷: the FIRST pop is the right operand. For "8 3 -", pop 3 (call it b), then 8 (a), and compute a − b = 5, not 3 − 8.

Division that truncates toward zero

Many problems say integer division "truncates toward zero", as in C, C++ and Java: 7 ÷ 2 = 3 and −7 ÷ 2 = −3. Python's // rounds DOWN (toward minus infinity), so −7 // 2 is −4. int(a / b) truncates, but it goes through a float, which can lose precision for very large numbers. A safe integer way is to divide the absolute values and put the sign back.

python
print(-7 // 2)        # Output: -4  (floor: rounds down)
print(int(-7 / 2))    # Output: -3  (toward zero, via a float)

def div_trunc(a, b):
    q = abs(a) // abs(b)
    return -q if (a < 0) != (b < 0) else q

print(div_trunc(-7, 2), div_trunc(7, -2), div_trunc(-7, -2))   # Output: -3 -3 3

Min-stack: the minimum in O(1)

A min-stack supports push, pop, top and get_min, all in O(1). Calling min(stack) would be O(n). The trick: store next to each value the minimum of the stack at the moment it was pushed. The top pair always knows the current minimum, and popping brings back the older minimum automatically. It costs O(n) extra space.

python
stack = []                        # pairs (value, minimum so far)
for x in [5, 3, 7, 3]:
    low = min(x, stack[-1][1]) if stack else x
    stack.append((x, low))
print(stack)          # Output: [(5, 5), (3, 3), (7, 3), (3, 3)]
stack.pop()
stack.pop()
print(stack[-1][1])   # Output: 3
stack.pop()
print(stack[-1][1])   # Output: 5

Common mistakes

  • Popping or peeking an empty stack (IndexError). Fix: check if stack: first and decide what to return.
  • In the bracket check, forgetting the final "is the stack empty?" test, so "((" passes. Fix: return not stack.
  • Swapping operands in RPN and computing b − a. Fix: the first pop is the RIGHT operand.
  • Using // when the task says "truncate toward zero". Fix: divide absolute values and fix the sign.
  • Using insert(0, x) and pop(0) as the stack top: both are O(n). Fix: push and pop at the end.
  • A min-stack that calls min() on every get_min. Fix: store the running minimum with each item.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Stacks · 1/8

Stacks

This lesson is about stacks: last in, first out.

Prefer a video by a teacher? Find free videos on “stack data structure valid parentheses evaluate reverse polish notation min stack” on YouTube ↗

In real life: Undo in a text editor

Editors such as the ones used for writing code or documents keep every change on an undo stack. Ctrl+Z pops the latest change and pushes it onto a redo stack; Ctrl+Y pops from the redo stack and pushes it back. Typing something new clears the redo stack, because the old future no longer applies. Real editors group keystrokes into larger changes, but the two-stack idea is the same.

python
undo, redo = [], []
text = ""
for word in ["Namaste", " from", " Pune"]:
    undo.append(text)        # remember the state before each change
    text += word
    redo.clear()
print(text)
redo.append(text)
text = undo.pop()            # Ctrl+Z
print(text)
undo.append(text)
text = redo.pop()            # Ctrl+Y
print(text)
Shows Namaste from Pune, then Namaste from, then Namaste from Pune again.

Practice (0/3 done)

Task 1 · Code · Python

Write is_valid_brackets(s) that returns True if every bracket in s is closed by the same kind of bracket in the right order. The brackets are ( ) [ ] { }; every other character (letters, digits, spaces) is ignored. Use a stack: O(n) time. Example: is_valid_brackets("a(b[c]d)e") returns True and is_valid_brackets("([)]") returns False.

Task 2 · Code · Python

Write eval_rpn(tokens) that evaluates a postfix (Reverse Polish) expression given as a list of strings. Numbers are integers (they can be negative, like "-11"); the operators are "+", "-", "*" and "/". Division between integers TRUNCATES TOWARD ZERO (7 / -2 is -3, not -4), and there is never a division by zero. The expression is always valid. Example: eval_rpn(["2", "1", "+", "3", "*"]) returns 9.

Task 3 · Code · Python

Complete the class MinStack with push(x), pop(), top() and get_min(), each in O(1) time. pop() removes the top item and returns it; top() returns the top item without removing it; get_min() returns the smallest item in the stack. On an empty stack, pop(), top() and get_min() return None. Values can repeat and can be negative.

Quick quiz

Question 1

1.You push 1, 2 and 3, pop once, then push 4. What does peek return now?

Question 2

2.Which Python list operations make a stack with O(1) push and pop?

Question 3

3.What is the value of the postfix expression "6 2 / 3 -"?

Question 4

4.With division that truncates toward zero, what is −9 ÷ 4?

Question 5

5.How does a min-stack answer get_min in O(1)?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

You push 1, 2 and 3, pop once, then push 4. What does peek return now?

Answer: 4

Popping removes 3; then 4 goes on top of 2.

Which Python list operations make a stack with O(1) push and pop?

Answer: append and pop()

Working at the end needs no shifting. Anything at index 0 shifts the whole list, O(n).

What is the value of the postfix expression "6 2 / 3 -"?

Answer: 0

6 / 2 = 3, then 3 − 3 = 0.

With division that truncates toward zero, what is −9 ÷ 4?

Answer: −2

−2.25 truncated toward zero is −2. Python's −9 // 4 would give −3.

How does a min-stack answer get_min in O(1)?

Answer: Each entry stores the minimum of the stack at the moment it was pushed

The top entry already knows the current minimum, and popping reveals the older one.

What is the time complexity of push and pop?Related

Answer: O(1)

Only the top is touched.

From Stacks

s = []; s.append(1); s.append(2); s.append(3); s.pop(); What does s.pop() return now?Related

Answer: 2

The first pop removed 3. The top is now 2.

From Stacks and queues

Which order does a stack follow?Related

Answer: LIFO

Last in, first out.

From Queues, stacks and priority queues

What does Navigator.pop(context) do?Related

Answer: Removes the top screen from the stack

Back to the previous route.

From Navigator basics

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 4 more topics in “Stacks, queues and linked lists” before its exam: Queues and deques, Monotonic stacks and queues, Linked lists, Fast and slow pointers and merging lists.
  2. Module 4 exam: Stacks, queues and linked lists · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Recursion and backtracking. 61 topics left in the course before the final exam.

← Previous: Sliding window: variable size