Trees, Graphs & Sorting
Binary Trees — BFS & DFS
class TreeNode {
constructor(
public val: number,
public left: TreeNode | null = null,
public right: TreeNode | null = null
) {}
}
// DFS — Inorder (left, root, right) → sorted for BST
function inorder(root: TreeNode | null): number[] {
if (!root) return [];
return [...inorder(root.left), root.val, ...inorder(root.right)];
}
// Iterative inorder
function inorderIterative(root: TreeNode | null): number[] {
const result: number[] = [];
const stack: TreeNode[] = [];
let curr: TreeNode | null = root;
while (curr || stack.length) {
while (curr) { stack.push(curr); curr = curr.left; }
curr = stack.pop()!;
result.push(curr.val);
curr = curr.right;
}
return result;
}
// BFS — Level order traversal
function levelOrder(root: TreeNode | null): number[][] {
if (!root) return [];
const result: number[][] = [];
const queue: TreeNode[] = [root];
while (queue.length) {
const level: number[] = [];
const size = queue.length;
for (let i = 0; i < size; i++) {
const node = queue.shift()!;
level.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
result.push(level);
}
return result;
}
// Max depth
function maxDepth(root: TreeNode | null): number {
if (!root) return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}Graph Traversal
type Graph = Map<number, number[]>;
// BFS — shortest path in unweighted graph
function bfs(graph: Graph, start: number, target: number): number {
const visited = new Set([start]);
const queue: [number, number][] = [[start, 0]]; // [node, distance]
while (queue.length) {
const [node, dist] = queue.shift()!;
if (node === target) return dist;
for (const neighbor of graph.get(node) ?? []) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
queue.push([neighbor, dist + 1]);
}
}
}
return -1;
}
// DFS — detect cycle, connected components
function dfs(graph: Graph, node: number, visited: Set<number>): void {
visited.add(node);
for (const neighbor of graph.get(node) ?? []) {
if (!visited.has(neighbor)) dfs(graph, neighbor, visited);
}
}
function countComponents(n: number, edges: [number, number][]): number {
const graph: Graph = new Map();
for (let i = 0; i < n; i++) graph.set(i, []);
for (const [u, v] of edges) {
graph.get(u)!.push(v);
graph.get(v)!.push(u);
}
const visited = new Set<number>();
let count = 0;
for (let i = 0; i < n; i++) {
if (!visited.has(i)) { dfs(graph, i, visited); count++; }
}
return count;
}Sorting Algorithms
// Merge Sort — O(n log n) stable
function mergeSort(arr: number[]): number[] {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid)));
}
function merge(left: number[], right: number[]): number[] {
const result: number[] = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
result.push(left[i] <= right[j] ? left[i++] : right[j++]);
}
return [...result, ...left.slice(i), ...right.slice(j)];
}
// Quick Sort — O(n log n) average, O(n²) worst, in-place
function quickSort(arr: number[], lo = 0, hi = arr.length - 1): void {
if (lo < hi) {
const pivot = partition(arr, lo, hi);
quickSort(arr, lo, pivot - 1);
quickSort(arr, pivot + 1, hi);
}
}
function partition(arr: number[], lo: number, hi: number): number {
const pivot = arr[hi];
let i = lo - 1;
for (let j = lo; j < hi; j++) {
if (arr[j] <= pivot) { i++; [arr[i], arr[j]] = [arr[j], arr[i]]; }
}
[arr[i + 1], arr[hi]] = [arr[hi], arr[i + 1]];
return i + 1;
}
// Binary Search — O(log n)
function binarySearch(arr: number[], target: number): number {
let lo = 0, hi = arr.length - 1;
while (lo <= hi) {
const mid = lo + Math.floor((hi - lo) / 2);
if (arr[mid] === target) return mid;
else if (arr[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}Stack & Queue
// Valid parentheses — stack pattern
function isValid(s: string): boolean {
const stack: string[] = [];
const pairs: Record<string, string> = { ')': '(', ']': '[', '}': '{' };
for (const c of s) {
if ('([{'.includes(c)) stack.push(c);
else if (stack.pop() !== pairs[c]) return false;
}
return stack.length === 0;
}
// Monotonic stack — next greater element
function nextGreaterElement(nums: number[]): number[] {
const result = new Array(nums.length).fill(-1);
const stack: number[] = []; // indices
for (let i = 0; i < nums.length; i++) {
while (stack.length && nums[stack[stack.length - 1]] < nums[i]) {
result[stack.pop()!] = nums[i];
}
stack.push(i);
}
return result;
}
// Min Stack (O(1) getMin)
class MinStack {
private stack: number[] = [];
private minStack: number[] = [];
push(val: number) {
this.stack.push(val);
this.minStack.push(Math.min(val, this.minStack[this.minStack.length - 1] ?? val));
}
pop() { this.stack.pop(); this.minStack.pop(); }
top() { return this.stack[this.stack.length - 1]; }
getMin() { return this.minStack[this.minStack.length - 1]; }
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free