DAY 28 / 30 · WEEK 4

Pattern Recognition Masterclass

Goal of the day

Concept

Days 1 through 27 each taught "here is how pattern X works" — and each one came with the single biggest hint of all: the day number itself told you which pattern to use before you'd even read the problem. A real interview strips that hint away completely. You get a paragraph of prose and a blank editor, and the actual test is whether you can look at that paragraph and know, within the first minute, which toolbox to open. Closing that gap — cold recognition, not just "I remember how sliding window works when someone tells me it's a sliding window problem" — is the single highest-leverage thing left to practice.

A reliable 3-step process gets you there:

  1. What's the data shape? A flat array/string, a linked chain, a tree/BST, a general graph (nodes with arbitrary connections), or no explicit structure at all — just a sequence of decisions to make (that last one is usually DP or greedy territory).
  2. What's the goal/constraint phrasing? Contiguous range? Already sorted, or benefits from being sorted? Need the current min/max repeatedly? Counting distinct ways? Reachability (yes/no)? An optimal sequence of choices?
  3. Match shape + goal to the narrowest pattern that fits, and sanity-check against the signal words below.

One honest caveat: some problems deliberately combine two patterns, and this course has built several of them on purpose — Day 14's quickselect (partition + halving), Day 21's BST validation (a stack doing a tree traversal's job), Day 26/27's coin change (the exact same problem, correct under DP, wrong under greedy). Recognition isn't always "pick the one right answer" — sometimes it's "which two patterns compose, and in what order."

Diagram: the master dispatch — which week's toolkit do I need?

Flat array/string, one pass or two ends moving? Week 1 patterns (see Day 7's flowchart) Need it sorted, searching a sorted range, or identical subproblems? Week 2 patterns (see Day 14's flowchart) Already a list/stack/queue/tree, question is traversal or order? Week 3 patterns (see Day 21's flowchart) Need the current min/max from a changing set, repeatedly? Heap (Day 22) Nodes connect arbitrarily, not just parent to child? Graph BFS/DFS/ shortest path/topo sort (Day 23/24) Sequence of decisions, overlapping subproblems — is greedy provably safe? yes: Greedy (Day 27) no: DP (Day 25/26) Check top to bottom. Rows 1-3 route you to a sub-flowchart you already have — Day 28's job is knowing WHICH one to open first.

Signal words — problem phrasing → pattern

This is the fast lookup table for the 30-second recognition window. Scan for the phrase, not the exact wording — interviewers rarely use these words verbatim, but the underlying signal is the same.

Signal in the problemPatternDay
"pair that sums to X," "two elements that..."Hash Map (unsorted) or Two Pointer (sorted)6 / 4
"longest/shortest/max/min ... contiguous substring/subarray"Sliding Window5
"palindrome," "reverse in place," converging from both endsTwo Pointer4
"frequency," "anagram," "duplicate," "group by"Hash Map / Set6
"kth largest/smallest," "top k," a running min/max as data streams inHeap22
"in a sorted array," "search space is monotonic"Binary Search12 / 13
"detect a cycle," "find the middle" (linked list)Fast/Slow Pointers16
"valid parentheses/brackets," "next greater element," "undo"Stack17
"sliding window maximum," "process in the order added"Queue / Deque18
"level order," "shortest path (unweighted)," "fewest hops/steps"BFS19 / 24
"explore all paths," "backtrack," "all combinations/permutations"DFS / Recursion9 / 19 / 23
"inorder gives sorted order," "predecessor/successor"Binary Search Tree20
"connections/network," "islands," "prerequisites"Graph23 / 24
"minimum/maximum ways to reach," "count distinct ways"Dynamic Programming25 / 26
"fewest coins/jumps/cost," "can I reach the end"DP — check greedy-choice property before trusting greedy25 / 26 / 27
"schedule non-overlapping," "meeting rooms," "activity selection"Greedy27

Interactive: pattern recognition drill

8 unlabeled problem statements. Pick the pattern before checking the reasoning — this is the exact 30-second judgment call an interview asks for.

1. "Given a string, find the length of the longest substring without repeating characters."

2. "Given a sorted array, determine if a target value exists, in O(log n) time."

3. "Given the head of a linked list, determine whether it has a cycle."

4. "Given a binary tree, return its level-order traversal."

5. "Given coin denominations and an amount, find the fewest coins needed to make it."

6. "Given a list of intervals, find the minimum number to remove so the rest don't overlap."

7. "Given a grid of 1s and 0s, count the number of islands (connected groups of 1s)."

8. "Given a stream of numbers arriving one at a time, continuously report the kth largest seen so far."

The code: every core template, side by side

Not one new algorithm today — the reference sheet of every pattern's minimal skeleton, so you can scan straight to the shape you need mid-interview.

// TWO POINTERS (Day 4) — converge from both ends
function twoPointerTemplate(arr) {
  let lo = 0, hi = arr.length - 1;
  while (lo < hi) {
    // inspect arr[lo] and arr[hi], then narrow toward the middle
    if (/* need a bigger value */ false) lo++;
    else hi--;
  }
}

// SLIDING WINDOW (Day 5) — grow/shrink a contiguous range
function slidingWindowTemplate(arr) {
  let left = 0;
  for (let right = 0; right < arr.length; right++) {
    // expand the window to include arr[right]
    while (/* window is invalid */ false) {
      left++;                          // shrink from the left until valid again
    }
    // window [left, right] is valid here — record a result
  }
}

// HASH MAP FREQUENCY (Day 6) — count/lookup in O(1) amortized
function frequencyTemplate(arr) {
  const seen = new Map();
  for (const x of arr) seen.set(x, (seen.get(x) || 0) + 1);
  return seen;
}

// BINARY SEARCH — exact match (Day 12)
function binarySearchTemplate(nums, target) {
  let lo = 0, hi = nums.length - 1;
  while (lo <= hi) {
    const mid = lo + Math.floor((hi - lo) / 2);
    if (nums[mid] === target) return mid;
    else if (nums[mid] < target) lo = mid + 1;
    else hi = mid - 1;
  }
  return -1;
}

// BFS (Day 19/24) — level order or shortest path, uses a QUEUE
function bfsTemplate(start, getNeighbors) {
  const visited = new Set([start]);
  const queue = [start];
  while (queue.length > 0) {
    const node = queue.shift();
    for (const next of getNeighbors(node)) {
      if (!visited.has(next)) { visited.add(next); queue.push(next); }
    }
  }
}

// DFS (Day 9/19/23) — full-depth exploration, recursion or an explicit STACK
function dfsTemplate(node, getNeighbors, visited = new Set()) {
  if (visited.has(node)) return;
  visited.add(node);
  for (const next of getNeighbors(node)) dfsTemplate(next, getNeighbors, visited);
}

// DYNAMIC PROGRAMMING (Day 25/26) — cache overlapping subproblems
function dpTemplate(n) {
  const dp = new Array(n + 1).fill(0);
  // seed the base case(s) here
  for (let i = 1; i <= n; i++) {
    // dp[i] = combine(dp[i-1], dp[i-2], ...) — sum, max, or min, depending on the problem
  }
  return dp[n];
}

// GREEDY (Day 27) — sort by the property that makes the choice safe, then one pass
function greedyTemplate(items) {
  items.sort((a, b) => 0 /* the key that makes THIS greedy choice provably safe */);
  let result = 0;
  for (const item of items) {
    // make the locally-best choice and never revisit it
  }
  return result;
}

Worked example: applying the 3-step process cold

Problem: "Given a string, return true if you can rearrange its characters to form a palindrome."

  1. Data shape: a flat string — Week 1 territory.
  2. Goal phrasing: "can be rearranged" is the key word. It explicitly says order doesn't matter — which immediately rules out two-pointer and sliding window (both depend on position/order). If order is irrelevant and only counts matter, that's a hash map / frequency-counting signal (Day 6).
  3. Match: a string's characters can be rearranged into a palindrome if and only if at most one character has an odd count (that lone odd-count character sits in the middle; every other character needs an even count to mirror on both sides).
function canFormPalindrome(s) {
  const freq = new Map();
  for (const ch of s) freq.set(ch, (freq.get(ch) || 0) + 1);
  let oddCount = 0;
  for (const count of freq.values()) if (count % 2 !== 0) oddCount++;
  return oddCount <= 1;
}
// canFormPalindrome("civic") -> true (already a palindrome)
// canFormPalindrome("ivicc") -> true (rearranges to "civic")
// canFormPalindrome("hello") -> false (too many odd-count characters)

Complexity — every pattern from the course, at a glance

PatternTypical timeTypical spaceDay
Two PointerO(n)O(1)4
Sliding WindowO(n)O(1) – O(k)5
Hash Map / SetO(n)O(n)6
Comparison sorting (merge/quick)O(n log n)O(1) – O(n)8 / 10 / 11
Binary SearchO(log n)O(1)12 / 13
Recursion (naive / memoized)O(2²) naive, O(n) memoizedO(n) call stack9 / 25
Linked list op at a known nodeO(1)O(1)15 / 16
Stack / Queue opO(1)O(n)17 / 18
BFS / DFS traversalO(V + E)O(V)19 / 23
BST search/insert (iterative)O(h)O(1)20
Heap insert/extractO(log n)O(n)22
Graph shortest path (unweighted) / topo sortO(V + E)O(V)24
Dynamic Programming (1D)O(n) – O(n × options)O(1) – O(n)25 / 26
GreedyO(n log n) (sort-dominated)O(1) – O(n)27

Interview corner

3 more problems — recognize first, then solve

1. Product of Array Except Self (Medium — LeetCode: Product of Array Except Self)

Given an array, return an array where each element is the product of every OTHER element, without using division. Keyword-only pattern-matching ("array," "product") could mislead toward a hash map — the real signal is "combine information from both sides," which points to a prefix/suffix pass instead.

2. 3Sum Closest (Medium — LeetCode: 3Sum Closest)

Given an array and a target, find the sum of 3 numbers closest to the target. The exact same sort-then-two-pointer shape as Day 11's 3Sum practice problem — the only change is the termination condition (closest, not exact).

3. Word Search (Medium — LeetCode: Word Search)

Given a grid of letters and a word, return whether the word can be traced through adjacent cells (up/down/left/right), using each cell at most once. Never labeled a "graph" or a "tree" — but a grid with adjacency IS a graph, and "trace a path" IS DFS with backtracking.

Quiz

1. What's the first question to ask when recognizing a pattern in a cold problem?

2. What's the key differentiator between sliding window and two-pointer?

3. The phrase "rearrange the characters" in a problem statement rules out which kinds of patterns?

4. True or false: a problem can be graph-shaped even if it never uses the word "graph."

5. When should you fall back to brute force during pattern recognition?