Skip to main content

Algorithms & LeetCode

Coding interviews test your ability to solve problems efficiently. The good news: there are roughly 15 patterns that cover ~90% of interview questions. Master these patterns and you can tackle almost any problem.

How to Approach Coding Problems

The UMPIRE Method

StepAction
UnderstandRestate the problem, ask clarifying questions
MatchWhich pattern does this fit?
PlanWrite pseudocode before coding
ImplementCode the solution
ReviewTest with examples, edge cases
EvaluateAnalyze time/space complexity

Time Complexity Cheat Sheet

ComplexityNameExample10⁶ ops at 10⁸/sec
O(1)ConstantHash table lookupinstant
O(log n)LogarithmicBinary search~20 µs
O(n)LinearSingle loop~10 ms
O(n log n)LinearithmicMerge sort~200 ms
O(n²)QuadraticNested loops~3 hours ❌
O(2ⁿ)ExponentialBrute force subsetscenturies ❌

The 15 Core Patterns

1. Two Pointers

Use when: Array/string problem, looking for a pair with a condition, removing elements in-place

Template:

function twoPointers(arr) {
let left = 0;
let right = arr.length - 1;

while (left < right) {
// Process pair
if (condition) {
left++;
} else {
right--;
}
}
}

Classic problems: Two Sum (sorted), Valid Palindrome, 3Sum, Container With Most Water


2. Sliding Window

Use when: Subarray/substring of fixed or variable size, running sum/max/min

Template:

function slidingWindow(arr, k) {
let windowSum = 0;
let maxSum = -Infinity;

for (let i = 0; i < arr.length; i++) {
windowSum += arr[i]; // Add right element

if (i >= k) {
windowSum -= arr[i - k]; // Remove left element
}

if (i >= k - 1) {
maxSum = Math.max(maxSum, windowSum);
}
}

return maxSum;
}

Classic problems: Maximum Sum Subarray of Size K, Longest Substring Without Repeating Characters, Minimum Window Substring


3. Fast & Slow Pointers

Use when: Linked list cycle detection, finding the middle of a list, palindrome detection

Template:

function hasCycle(head) {
let slow = head;
let fast = head;

while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;

if (slow === fast) return true; // Cycle detected
}

return false;
}

Classic problems: Linked List Cycle, Happy Number, Find the Duplicate Number, Middle of Linked List


Use when: Sorted array, searching for a boundary/target, answer can be binary-searched (feasibility check)

Template:

function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;

while (left <= right) {
const mid = Math.floor((left + right) / 2);

if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}

return -1; // Not found
}

// Search for leftmost position (lower bound)
function lowerBound(arr, target) {
let left = 0;
let right = arr.length;

while (left < right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] < target) left = mid + 1;
else right = mid;
}

return left;
}

Classic problems: Binary Search, Search in Rotated Sorted Array, Find First and Last Position, Koko Eating Bananas, Capacity to Ship Packages


Use when: Shortest path in unweighted graph, level-by-level traversal, "minimum number of steps"

Template:

function bfs(graph, start, end) {
const queue = [start];
const visited = new Set([start]);
let distance = 0;

while (queue.length > 0) {
const levelSize = queue.length;

for (let i = 0; i < levelSize; i++) {
const node = queue.shift();

if (node === end) return distance;

for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
queue.push(neighbor);
}
}
}

distance++;
}

return -1; // Not reachable
}

Classic problems: Number of Islands, Word Ladder, Rotting Oranges, Shortest Path in Binary Matrix


Use when: Explore all paths, tree traversal, connected components, permutations/combinations

Template (recursive):

function dfs(node, visited, graph) {
if (!node || visited.has(node)) return;

visited.add(node);

// Process node
console.log(node);

for (const neighbor of graph[node]) {
dfs(neighbor, visited, graph);
}
}

// DFS with backtracking
function backtrack(result, current, choices) {
if (/* base case */) {
result.push([...current]);
return;
}

for (const choice of choices) {
current.push(choice); // Make choice
backtrack(result, current, remainingChoices);
current.pop(); // Undo choice
}
}

Classic problems: Number of Islands, Clone Graph, Course Schedule, All Permutations, Subsets, Combination Sum


7. Dynamic Programming

Use when: Problem has overlapping subproblems + optimal substructure. Usually "min/max/count" problems.

Steps:

  1. Define the state (what does dp[i] mean?)
  2. Define the transition (how does dp[i] relate to dp[i-1]?)
  3. Base case
  4. Final answer

Template (1D):

function dp1D(n) {
const dp = new Array(n + 1).fill(0);
dp[0] = 1; // Base case

for (let i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]; // Transition
}

return dp[n];
}

// Often, optimize to O(1) space:
function dp1D_optimized(n) {
let prev2 = 0, prev1 = 1;

for (let i = 1; i < n; i++) {
[prev2, prev1] = [prev1, prev1 + prev2];
}

return prev1;
}

Template (2D):

function dp2D(matrix) {
const m = matrix.length;
const n = matrix[0].length;
const dp = Array.from({ length: m }, () => new Array(n).fill(0));

// Fill base cases (row 0, col 0)
// Fill rest using transitions
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + matrix[i][j];
}
}

return dp[m-1][n-1];
}

Classic problems: Climbing Stairs, House Robber, Coin Change, Longest Common Subsequence, 0/1 Knapsack, Edit Distance


8. Heap / Priority Queue

Use when: "Top K", "K closest", streaming data, merging sorted lists

Template:

// Min-heap using a sorted array (for interviews, use a library in practice)
class MinHeap {
constructor() { this.heap = []; }

push(val) {
this.heap.push(val);
this.bubbleUp(this.heap.length - 1);
}

pop() {
const min = this.heap[0];
const last = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = last;
this.sinkDown(0);
}
return min;
}

peek() { return this.heap[0]; }
size() { return this.heap.length; }

bubbleUp(i) {
while (i > 0) {
const parent = Math.floor((i - 1) / 2);
if (this.heap[parent] > this.heap[i]) {
[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];
i = parent;
} else break;
}
}

sinkDown(i) {
const n = this.heap.length;
while (true) {
let smallest = i;
const left = 2 * i + 1;
const right = 2 * i + 2;

if (left < n && this.heap[left] < this.heap[smallest]) smallest = left;
if (right < n && this.heap[right] < this.heap[smallest]) smallest = right;

if (smallest !== i) {
[this.heap[smallest], this.heap[i]] = [this.heap[i], this.heap[smallest]];
i = smallest;
} else break;
}
}
}

// Top K frequent elements
function topKFrequent(nums, k) {
const freq = new Map();
for (const n of nums) freq.set(n, (freq.get(n) || 0) + 1);

const heap = new MinHeap(); // Min-heap of size k
for (const [num, count] of freq) {
heap.push([count, num]);
if (heap.size() > k) heap.pop();
}

return heap.heap.map(([count, num]) => num);
}

Classic problems: Kth Largest Element, Top K Frequent Elements, Find Median from Data Stream, Merge K Sorted Lists, Task Scheduler


9. Graph Algorithms

Topological Sort (for dependency ordering):

function topoSort(numNodes, edges) {
// Build adjacency list and in-degree count
const adj = Array.from({ length: numNodes }, () => []);
const inDegree = new Array(numNodes).fill(0);

for (const [from, to] of edges) {
adj[from].push(to);
inDegree[to]++;
}

// Start with nodes that have no dependencies
const queue = [];
for (let i = 0; i < numNodes; i++) {
if (inDegree[i] === 0) queue.push(i);
}

const result = [];
while (queue.length > 0) {
const node = queue.shift();
result.push(node);

for (const neighbor of adj[node]) {
inDegree[neighbor]--;
if (inDegree[neighbor] === 0) queue.push(neighbor);
}
}

// If result.length !== numNodes, there's a cycle
return result.length === numNodes ? result : [];
}

Union-Find (Disjoint Set Union):

class UnionFind {
constructor(n) {
this.parent = Array.from({ length: n }, (_, i) => i);
this.rank = new Array(n).fill(0);
this.components = n;
}

find(x) {
if (this.parent[x] !== x) {
this.parent[x] = this.find(this.parent[x]); // Path compression
}
return this.parent[x];
}

union(x, y) {
const px = this.find(x);
const py = this.find(y);
if (px === py) return false;

// Union by rank
if (this.rank[px] < this.rank[py]) {
this.parent[px] = py;
} else if (this.rank[px] > this.rank[py]) {
this.parent[py] = px;
} else {
this.parent[py] = px;
this.rank[px]++;
}

this.components--;
return true;
}

connected(x, y) {
return this.find(x) === this.find(y);
}
}

LeetCode Problem Map

Easy Problems (Build Foundation)

#ProblemPatternTimeSpace
1Two SumHash TableO(n)O(n)
21Merge Two Sorted ListsTwo PointersO(n+m)O(1)
121Best Time to Buy/Sell StockSliding WindowO(n)O(1)
141Linked List CycleFast/SlowO(n)O(1)
206Reverse Linked ListIterativeO(n)O(1)
242Valid AnagramHash TableO(n)O(1)
344Reverse StringTwo PointersO(n)O(1)
704Binary SearchBinary SearchO(log n)O(1)

Medium Problems (Core Patterns)

#ProblemPatternTimeSpace
3Longest Substring Without Repeating CharsSliding WindowO(n)O(k)
153SumTwo PointersO(n²)O(1)
33Search in Rotated Sorted ArrayBinary SearchO(log n)O(1)
39Combination SumBacktrackingO(2ⁿ)O(n)
46PermutationsBacktrackingO(n!)O(n)
53Maximum SubarrayKadane's AlgoO(n)O(1)
56Merge IntervalsSortingO(n log n)O(n)
98Validate BSTDFSO(n)O(h)
102Binary Tree Level OrderBFSO(n)O(n)
200Number of IslandsDFS/BFSO(m×n)O(m×n)
207Course ScheduleTopo SortO(V+E)O(V+E)
300Longest Increasing SubsequenceDPO(n log n)O(n)
322Coin ChangeDPO(amount×n)O(amount)
347Top K Frequent ElementsHeapO(n log k)O(n)
417Pacific Atlantic Water FlowDFSO(m×n)O(m×n)
424Longest Repeating Char ReplacementSliding WindowO(n)O(1)

Hard Problems (Advanced)

#ProblemPatternTimeSpace
4Median of Two Sorted ArraysBinary SearchO(log(m+n))O(1)
23Merge K Sorted ListsHeapO(n log k)O(k)
42Trapping Rain WaterTwo PointersO(n)O(1)
72Edit DistanceDP (2D)O(m×n)O(m×n)
76Minimum Window SubstringSliding WindowO(n)O(k)
295Find Median from Data StreamTwo HeapsO(log n)O(n)
297Serialize/Deserialize BSTDFSO(n)O(n)
312Burst BalloonsDPO(n³)O(n²)

Quick Reference: When to Use What

SignalPattern
Sorted array + find pair/tripletTwo Pointers
Contiguous subarray/substring with conditionSliding Window
Linked list cycle, middle elementFast/Slow Pointers
Sorted input + searchBinary Search
Tree/graph traversal by levelBFS
Tree/graph traversal by depth, all pathsDFS
Min/max count/waysDynamic Programming
Top/smallest K elementsHeap
Dependency orderingTopological Sort
Connected componentsUnion-Find

See the individual pattern pages for full explanations and practice problems.