Lesson 16 — Stack: last-in, first-out matching

Day 15 · ~25 minutes · stack matching · Python

Tonight's problems are Valid Parentheses and Min Stack. Interviewers like them because they test one small question: when the newest thing must be resolved first, can you keep exactly that newest thing ready?

The invariant

A stack remembers the most recent unresolved opener — exactly what bracket nesting needs; a shadow stack of running minima makes getMin O(1).

A stack is last-in, first-out: the last item pushed is the first item popped. In Python, a list already works as a stack with append and pop (Python docs: using lists as stacks).

Valid Parentheses: the slow way first

The problem: a string has only brackets, and every closer must match the correct opener in the correct nesting order. A brute force approach is to repeatedly delete adjacent matched pairs: (), [], and {}. That can work, but it is O(n²): each cleanup pass scans the string again, and deeply nested input may need many passes.

The better question is sharper: when you see a closer, what opener is it trying to close? It must be the most recent unresolved opener. That is exactly the top of a stack.

Bracket matching with a stack 1. read '(' 2. read '[' 3. read ']' ([]) ([]) ([]) ( ( [ ( [ push opener new opener is top closer checks top match '[': pop it

The closer does not search the whole string; it checks the newest unresolved opener at the stack top.

def is_valid(s):
    need = {")": "(", "]": "[", "}": "{"}
    stack = []
    for ch in s:
        if ch not in need:
            stack.append(ch)             # unresolved opener
        elif not stack or stack.pop() != need[ch]:
            return False                 # no opener, or wrong one
    return not stack                     # nothing left unresolved

Notice the shape: push openers, pop only when a closer proves the top opener is the right one. If anything closes out of order, the invariant breaks immediately.

Transfer: same stack, new job

Min Stack: build a stack that supports push, pop, top, and getMin. Before opening the reveal, predict why one variable called min_value is not enough after pops.

Your prediction first — then read on.

A single variable forgets the previous minimum when the current minimum is popped. So every push also records the minimum at that exact depth.

Min Stack values and shadow minima push sequence value stack min stack Each depth stores its own minimum 5 2 7 5 2 7 5 2 2 getMin() same height as values

The minimum stack changes in lockstep with the value stack, so getMin is just a peek at the top.

class MinStack:
    def __init__(self):
        self.vals, self.mins = [], []

    def push(self, x):
        self.vals.append(x)
        best = x if not self.mins else min(x, self.mins[-1])
        self.mins.append(best)           # min as of this depth

    def pop(self):
        self.mins.pop()
        return self.vals.pop()

    def top(self):
        return self.vals[-1]

    def getMin(self):
        return self.mins[-1]

The shadow stack moves in lockstep with the real stack. Pop a value, and you also pop the minimum that belonged to that depth.

What the trade buys you

ProblemApproachTimeSpace
Valid ParenthesesRepeated pair removalO(n²)O(n)
Valid ParenthesesStack matchingO(n)O(n)
Min StackScan for minimumO(n) getMinO(n)
Min StackShadow minimaO(1) operationsO(n)

Practice — answer before you scroll past

1. Which action closes the newest unresolved opener?

2. Spot the bug in this closer branch:

elif stack[-1] == need[ch]:
    stack.pop()
else:
    return False

3. What should the shadow min stack store?

4. Which problem uses opener matching directly?

Your move (tonight)

Solve these on LeetCode, in order, logging each in your Notion tracker with the cycle — predict → attempt → compare → encode:

  1. Valid Parentheses — predict the stack invariant, write the one-pass version, then test empty, single-closer, and nested cases.
  2. Min Stack — predict why the shadow stack must have the same length as the value stack, then implement every method.

For the encode step, write the invariant at the top of this page in your own words. That line is what revision days will test.

One primary source

Watch NeetCode — Valid Parentheses after your attempt, as the compare step. Listen for the moment he decides a closer must match the stack top.


Stuck or curious? Ask your teacher (the agent) — that's what it's for.