Stack functions
Each pattern below is something you will reach for while solving stack problems. Skim the short description, then copy the snippets for common situations.
Prefer Overview for how stacks work, and Problems for practice once problems are linked.
Array as a stack
In TypeScript, a plain array is already a stack if you only push and pop at the end.
push() / pop()
Grow and shrink from the end — the classic LIFO pair.
const stack: number[] = [];
// ——— push (top grows) ———
stack.push(7);
stack.push(3);
stack.push(9); // [7, 3, 9] · top is 9
// ——— pop (top leaves first) ———
const top = stack.pop(); // 9
// stack is [7, 3]
// ——— drain ———
while (stack.length > 0) {
const v = stack.pop()!;
// use v
}length as emptiness
Treat length === 0 as isEmpty. Guard before every pop.
function isEmpty(stack: unknown[]): boolean {
return stack.length === 0;
}
function safePop<T>(stack: T[]): T | undefined {
return stack.length === 0 ? undefined : stack.pop();
}Custom Stack class
Wrap the array when you want named methods and a clear public API.
class Stack
Thin wrapper around an array with push, pop, peek, and size.
class Stack<T> {
private readonly items: T[] = [];
push(value: T): void {
this.items.push(value);
}
pop(): T | undefined {
return this.items.pop();
}
peek(): T | undefined {
return this.items[this.items.length - 1];
}
get size(): number {
return this.items.length;
}
get isEmpty(): boolean {
return this.items.length === 0;
}
clear(): void {
this.items.length = 0;
}
}
const s = new Stack<number>();
s.push(1);
s.push(2);
s.peek(); // 2
s.pop(); // 2Peek & contains
Read the top, or ask whether a value sits somewhere in the pile.
peek()
Look at the last index without calling pop.
const stack = [7, 3, 9];
// ——— top without remove ———
const top = stack[stack.length - 1]; // 9
// stack unchanged
// ——— with a guard ———
function peek<T>(stack: T[]): T | undefined {
return stack.length === 0 ? undefined : stack[stack.length - 1];
}contains()
Scan from the top down, or use includes on the backing array.
const stack = [7, 3, 9];
// ——— array helper ———
stack.includes(3); // true
// ——— walk from top (matches “search from top”) ———
function contains<T>(stack: T[], target: T): boolean {
for (let i = stack.length - 1; i >= 0; i--) {
if (stack[i] === target) return true;
}
return false;
}Balanced parentheses
Push openers, pop on closers — the classic stack interview warm-up.
isBalanced()
Match brackets with a stack. Wrong closer or leftovers mean invalid.
const pairs: Record<string, string> = {
')': '(',
']': '[',
'}': '{',
};
function isBalanced(s: string): boolean {
const stack: string[] = [];
for (const ch of s) {
if (ch === '(' || ch === '[' || ch === '{') {
stack.push(ch);
continue;
}
const open = pairs[ch];
if (!open) continue; // ignore other chars
if (stack.pop() !== open) return false;
}
return stack.length === 0;
}
isBalanced('([])'); // true
isBalanced('([)]'); // falseUndo stack
Keep a history of states or commands so you can rewind one step at a time.
undo history
Push snapshots (or actions) on change; pop to restore the previous value.
type Edit = { before: string; after: string };
const history: Edit[] = [];
let text = '';
function typeText(next: string): void {
history.push({ before: text, after: next });
text = next;
}
function undo(): void {
const edit = history.pop();
if (!edit) return;
text = edit.before;
}
typeText('hi');
typeText('hi!');
undo(); // text is 'hi' againredo with two stacks
Undo pops from history onto a redo stack; redo pushes back.
const undoStack: string[] = [];
const redoStack: string[] = [];
let value = '';
function setValue(next: string): void {
undoStack.push(value);
redoStack.length = 0;
value = next;
}
function undo(): void {
if (undoStack.length === 0) return;
redoStack.push(value);
value = undoStack.pop()!;
}
function redo(): void {
if (redoStack.length === 0) return;
undoStack.push(value);
value = redoStack.pop()!;
}Monotonic stack
Keep values increasing or decreasing so the top is always the next useful candidate.
next greater element
Pop while the top is smaller than the current value, then push.
// ——— next greater to the right ———
function nextGreater(nums: number[]): number[] {
const n = nums.length;
const out = new Array<number>(n).fill(-1);
const stack: number[] = []; // indexes, increasing values
for (let i = 0; i < n; i++) {
while (stack.length > 0 && nums[stack.at(-1)!]! < nums[i]!) {
const j = stack.pop()!;
out[j] = nums[i]!;
}
stack.push(i);
}
return out;
}
nextGreater([2, 1, 2, 4, 3]); // [4, 2, 4, -1, -1]when to use it
Reach for a monotonic stack when each index needs the next larger or smaller neighbor.
// Pattern sketch (decreasing stack for “next smaller”):
// for each value x from left to right:
// while stack is not empty and top >= x: pop
// // top (if any) is the previous smaller
// push x
//
// Same idea runs right-to-left for “previous” answers.