Pattern Recognition Cheat Sheet

Match the Problem Shape to the Right Algorithm Family in Seconds

Pattern Recognition Cheat Sheet

Six recurring patterns cover the vast majority of interview problems — hash for duplicates, two pointers on sorted arrays, sliding window on substrings, BFS for shortest path, DP for optimal counts, and backtracking for enumeration.

4 min read Level 2/5 #dsa#interview#patterns
What you'll learn
  • Map a problem description to one of six canonical algorithm patterns
  • Implement a sliding-window frequency counter and a BFS shortest path in JS
  • Explain the trigger words that signal each pattern

Most interview problems are variations on a small set of patterns. Recognising the pattern early lets you skip to the right data structure and algorithm family instead of re-inventing from scratch under pressure.

The Six Patterns at a Glance

PatternTrigger wordsKey data structure
Hash / frequency countduplicate, anagram, “in O(1)”, countMap / Set
Two pointerssorted array, pair sum, palindrome, containertwo indices
Sliding windowsubarray / substring, longest, at most Kleft/right index
BFSshortest path, fewest steps, level orderQueue (array or deque)
Dynamic programmingcount ways, minimum cost, maximum value, overlapping sub-problemstable / memo Map
Backtrackinggenerate all, combinations, permutations, valid placementrecursion + undo

Hash: Find Any Duplicate in O(n)

function hasDuplicate(nums) {
  const seen = new Set();
  for (const n of nums) {
    if (seen.has(n)) return true;
    seen.add(n);
  }
  return false;
}

Sliding Window: Longest Substring with At Most K Distinct Characters

function longestKDistinct(s, k) {
  const freq = new Map();
  let left = 0;
  let best = 0;

  for (let right = 0; right < s.length; right++) {
    const c = s[right];
    freq.set(c, (freq.get(c) ?? 0) + 1);

    while (freq.size > k) {
      const l = s[left++];
      freq.set(l, freq.get(l) - 1);
      if (freq.get(l) === 0) freq.delete(l);
    }

    best = Math.max(best, right - left + 1);
  }
  return best;
}

BFS: Shortest Path in an Unweighted Grid

function shortestPath(grid, start, end) {
  const [rows, cols] = [grid.length, grid[0].length];
  const visited = Array.from({ length: rows }, () => new Array(cols).fill(false));
  const queue = [[...start, 0]]; // [row, col, steps]
  visited[start[0]][start[1]] = true;
  const dirs = [[1,0],[-1,0],[0,1],[0,-1]];

  while (queue.length) {
    const [r, c, steps] = queue.shift();
    if (r === end[0] && c === end[1]) return steps;
    for (const [dr, dc] of dirs) {
      const nr = r + dr;
      const nc = c + dc;
      if (nr >= 0 && nr < rows && nc >= 0 && nc < cols
          && !visited[nr][nc] && grid[nr][nc] !== 1) {
        visited[nr][nc] = true;
        queue.push([nr, nc, steps + 1]);
      }
    }
  }
  return -1; // no path
}

Choosing Between DP and Backtracking

Both deal with choices, but they differ in goal:

  • DP — you want one optimal value (min cost, max profit, number of ways). Sub-problems overlap, so you cache results.
  • Backtracking — you want all valid solutions (all permutations, all valid parenthesisations). You explore and undo.

If the problem says “count” or “minimum/maximum”, reach for DP first. If it says “list all” or “generate every”, reach for backtracking.

Up Next

Knowing the pattern is step one. Choosing the right complexity trade-off for your specific constraints is step two.

Complexity Trade-offs →