Coding

Coding Interview Patterns You Must Know

Grinding 500 random LeetCode problems is the slow way. Almost every coding interview question is one of a few recurring patterns — learn to recognise them and the problems start solving themselves.

Here's the thing nobody tells you when you start preparing for coding interviews: you are not expected to invent clever algorithms on the spot. The interviewer is checking whether you can recognise a familiar shape and apply a known technique to it.

That's great news, because there are only a handful of shapes. Learn these 8 coding interview patterns, learn the signal that points to each one, and you'll walk into the room pattern-matching instead of panicking. Let's go.


How to pick a pattern fast

Before the patterns themselves, internalise this: the problem statement almost always tells you which tool to grab. Train yourself to spot the signal.

The decision shortcut — map the problem's signal to the pattern before you write a line of code.

Keep that map in your head. Now here's each pattern, when to reach for it, and a quick taste of how it works.


1. Two Pointers

The signal: a sorted array (or string) where you're looking for a pair, a triplet, or you need to compare from both ends.

Instead of a nested loop (O(n²)), you walk two pointers inward from each end, moving them based on the comparison. It collapses the work to O(n).

Two pointers converge from both ends of a sorted array, skipping the nested loop entirely.
// Find two numbers in a sorted array that sum to target.
function twoSum(nums, target) {
  let left = 0, right = nums.length - 1;
  while (left < right) {
    const sum = nums[left] + nums[right];
    if (sum === target) return [left, right];
    if (sum < target) left++;     // need a bigger sum
    else right--;                 // need a smaller sum
  }
  return [];
}

2. Sliding Window

The signal: "longest / shortest / maximum" over a contiguous subarray or substring.

You keep a window that grows and shrinks across the array, updating an answer as you go — so each element is visited once instead of re-scanning ranges.

The window expands and contracts across the array; nothing gets re-scanned.
// Longest substring without repeating characters.
function longestUnique(s) {
  const seen = new Set();
  let left = 0, best = 0;
  for (let right = 0; right < s.length; right++) {
    while (seen.has(s[right])) seen.delete(s[left++]); // shrink
    seen.add(s[right]);                                // grow
    best = Math.max(best, right - left + 1);
  }
  return best;
}

3. Fast & Slow Pointers

The signal: a linked list (or a sequence) where you need to detect a cycle, find the middle, or spot a repeat.

Two pointers move at different speeds. If there's a loop, the fast one eventually laps the slow one and they meet — the classic "tortoise and hare".

// Detect a cycle in a linked list.
function hasCycle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;         // 1 step
    fast = fast.next.next;    // 2 steps
    if (slow === fast) return true;
  }
  return false;
}

4. Binary Search

The signal: the input is sorted, or you're searching a range of answers for the smallest/largest value that works.

Halve the search space every step — O(log n). The trick interviewers love: binary search isn't just for arrays, it's for any monotonic answer space ("what is the minimum capacity that ships everything in D days?").

function binarySearch(nums, target) {
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const mid = lo + ((hi - lo) >> 1); // avoids overflow
    if (nums[mid] === target) return mid;
    if (nums[mid] < target) lo = mid + 1;
    else hi = mid - 1;
  }
  return -1;
}

5. BFS & DFS (tree and graph traversal)

The signal: anything shaped like a tree or graph — levels, shortest path, connected components, "can you reach X from Y".

  • BFS (breadth-first) explores level by level using a queue — perfect for shortest paths in unweighted graphs.
  • DFS (depth-first) dives down one branch using recursion or a stack — great for exploring all paths or detecting cycles.
BFS visits node 1, then the level {2,3}, then {4,5,6}. DFS would dive 1 → 2 → 4 first.
// BFS over a tree, level by level.
function bfs(root) {
  const queue = [root], order = [];
  while (queue.length) {
    const node = queue.shift();
    order.push(node.val);
    for (const child of node.children) queue.push(child);
  }
  return order;
}

6. Backtracking

The signal: "generate all combinations / permutations / subsets", or a puzzle like Sudoku or N-Queens.

You build a candidate step by step, and the moment it can't lead to a valid solution you undo the last choice and try another. It's brute force with a brain.

// All subsets of a set.
function subsets(nums) {
  const result = [];
  function backtrack(start, path) {
    result.push([...path]);
    for (let i = start; i < nums.length; i++) {
      path.push(nums[i]);          // choose
      backtrack(i + 1, path);      // explore
      path.pop();                  // un-choose (backtrack)
    }
  }
  backtrack(0, []);
  return result;
}

7. Dynamic Programming

The signal: "how many ways…", "minimum/maximum cost…", and the problem breaks into overlapping subproblems whose answers you'd otherwise recompute.

The whole idea is to remember sub-answers instead of recomputing them — either top-down (memoised recursion) or bottom-up (filling a table). DP scares people, but every DP problem is just: define the subproblem, then combine sub-answers.

// Classic: Fibonacci, but the pattern generalises to most DP.
function fib(n) {
  const dp = [0, 1];
  for (let i = 2; i <= n; i++) dp[i] = dp[i - 1] + dp[i - 2];
  return dp[n];
}

Interview tip: when you smell DP, say it out loud and write the recurrence first ("the answer at i depends on i-1 and i-2"). The code follows easily once the recurrence is right.


8. Top-K Elements (Heaps)

The signal: "the K largest / smallest / most frequent" something.

A heap (priority queue) keeps the best K items as you stream through the data — O(n log k) instead of sorting everything at O(n log n). Reach for it whenever you see the words "top K", "K closest", or "K most frequent".

// Keep a min-heap of size k → its root is the kth largest.
// (Using a library/heap structure in a real interview.)
function kthLargest(nums, k) {
  const minHeap = new MinHeap();
  for (const n of nums) {
    minHeap.push(n);
    if (minHeap.size() > k) minHeap.pop(); // drop the smallest
  }
  return minHeap.peek();
}

The cheat sheet

Tape this to your monitor. When you read a problem, find the signal, grab the pattern:

If the problem says…Reach for
Sorted array, find a pairTwo Pointers
Longest/shortest contiguous substringSliding Window
Linked list cycle or middleFast & Slow Pointers
Sorted input, or "minimum X that works"Binary Search
Tree/graph, shortest path or levelsBFS
Tree/graph, all paths or cycle checkDFS
All combinations / permutationsBacktracking
Count ways, min/max cost, overlapping subproblemsDynamic Programming
Top / K most frequent / K closestHeap

How to actually practise this

Patterns only stick when you label problems as you solve them. Don't just get the green check — say which pattern it was and what signal gave it away. After 5–10 problems per pattern, you'll start reading a question and immediately knowing which tool to grab. That recognition speed is the whole game.

And remember: in the real interview, talk through the pattern before you code. Naming "this looks like a sliding-window problem because…" shows the interviewer exactly the structured thinking they're hiring for.

Reading is step one. Practising is what gets you hired.

Run a full AI mock interview — behavioral, coding, or system design — and get instant, honest feedback on exactly where you stand.

Practise a mock interview free