Valid Parentheses
The shape of the problem
Every closing bracket must match the most recent unmatched opener. You scan left-to-right once and decide valid or invalid at the end.
Signals to notice
Brute force first
Repeatedly scan the string and delete any adjacent `()`, `[]`, or `{}` pair. Valid iff the whole string collapses to empty. Each pass only removes innermost pairs, so worst case is O(n²).
The key insight
The most recent unmatched opener is always the next bracket that has to close. That is exactly the LIFO discipline of a stack, so a stack maps 1-to-1 to the constraint.
Trace it on ({[]})
( push → stack: [(
{ push → stack: [( {
[ push → stack: [( { [
] pop matches → stack: [( {
} pop matches → stack: [(
) pop matches → stack: [] ✓ empty → validWhat must stay true
The stack contains exactly the unmatched openers seen so far, in the order they appeared. Nothing else is ever on it.
Shape of the loop
for c in s: if c is opener: push c elif stack empty or top != match(c): return false else: pop return stack is empty
Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Returning true the moment every closer has matched. On input `(((`, every closer (there are none) has matched, but the stack still has three openers — you must check the stack is empty at the end.