1. The mental model
A stack is a pile of plates. You add to the top, inspect the top, and remove from the top. You never pull from the middle.
| Operation | C++ vector | JavaScript Array | Cost |
|---|---|---|---|
| push | st.push_back(x) | st.push(x) | O(1) amortised |
| top | st.back() | st.at(-1) | O(1) |
| pop | st.pop_back() | st.pop() | O(1) |
| empty | st.empty() | st.length === 0 | O(1) |
The invariant is the useful part: the top is the most recent unfinished thing.
2. The recognition signals
- Nested pairs: parentheses, tags, scopes, directory paths.
- “Undo”, “back”, or “most recent”.
- An expression whose later operator consumes earlier operands.
- Something waits until a future element resolves it.
- Recursive DFS rewritten iteratively.
Ask one question: if I pause this item, which paused item must I resume first? If the answer is “the newest one”, use a stack.
3. Three common stack shapes
Matching
Push every opener. A closer must match the top, because inner groups close before outer groups. That is Valid Parentheses.
Evaluation
Push operands. When an operator arrives, pop the inputs, compute, and push the result. That is Evaluate Reverse Polish Notation.
Carry extra information
Store {value, minimumSoFar} rather than only value. The top then answers both top() and
getMin() in O(1). This is a general pattern: if deleting the top would make a global value hard
to recover, store the value that was true at each depth. See Min Stack.
4. C++ and JavaScript templates
vector<int> st;
st.push_back(x);
int top = st.back();
st.pop_back();
const stack = [];
stack.push(x);
const top = stack.at(-1);
stack.pop();
Prefer a C++ vector while learning: it makes the actual storage visible and is easy to inspect.
Use std::stack<T> when you specifically want the interface to prevent iteration.
5. Traps
- Popping before checking empty. In C++,
back()on an empty vector is undefined behaviour. - Reversing operand order. After popping RPN operands, the first pop is
right, the second isleft. Subtraction and division expose the bug. - Using JavaScript
shift(). That is queue-like and O(n); stack work belongs at the array end. - Storing the wrong thing. Monotonic problems often need indices, not values, because the answer is a distance or width.
6. Learning gate
Before moving on, explain aloud why ([{}]) is valid but ([)] is not using only the sentence
“the top is the most recent unfinished thing.” Then implement all three operations in both
languages without autocomplete.