Pattern Recognition

Pattern recognition means extracting cues, matching proven templates, and selecting the fastest valid approach. Example: contiguous subarray often suggests sliding window, while repeated states usually suggest dynamic programming.

Read Signals
sorted? contiguous? pair?
Map Pattern
window, pointers, graph, DP
Eliminate
reject O(n^2) when n is large
Signal -> Candidate Patterns -> Eliminate -> Implement
Pattern-recognition workflow
Current Story Beat
Read constraints before coding.

Pattern Recognition Helper

A storytelling guide to map problem cues into the right algorithm quickly.
Continue

1. Extract Problem Signals

Scan for words like sorted, contiguous, shortest path, frequency, or repeated states.
Continue

2. Sliding Window Cues

Contiguous subarray or substring optimization usually points to sliding window.
Continue

3. Two-Pointers Cues

Sorted arrays, pair conditions, or palindrome checks often map to two pointers.
Continue

4. Hash Map Cues

Fast lookup, counting frequencies, and duplicate detection favor hash maps.
Continue

5. Graph Cues

Traversal, connectivity, or shortest path cues indicate BFS/DFS or Dijkstra.
Continue

6. Dynamic Programming Cues

Repeated states + optimal substructure = dynamic programming candidates.
Continue

7. Apply Workflow

Signal -> Candidate Patterns -> Eliminate -> Implement.
Continue

Interactive Practice

Classify a new problem statement by pattern.
Continue

Pattern Recognition Helper

Start with cue extraction before writing any code.

detectPattern.ts
function detectPattern(statement: string): string {
  const s = statement.toLowerCase();

  if (s.includes("contiguous") || s.includes("substring") || s.includes("subarray")) {
    return "sliding window";
  }
  if (s.includes("sorted") && (s.includes("pair") || s.includes("sum"))) {
    return "two pointers";
  }
  if (s.includes("palindrome")) {
    return "two pointers (or expand around center)";
  }
  if (s.includes("pair sum") || s.includes("two sum") || s.includes("duplicate") || s.includes("frequency")) {
    return "hash map";
  }
  if (s.includes("kth") || s.includes("top k") || s.includes("priority") || s.includes("smallest range")) {
    return "heap / priority queue";
  }
  if (s.includes("shortest path") && !s.includes("weighted")) {
    return "bfs";
  }
  if (s.includes("shortest path") && s.includes("weighted")) {
    return "dijkstra";
  }
  if (s.includes("graph") && (s.includes("traverse") || s.includes("connected") || s.includes("cycle"))) {
    return "dfs or bfs";
  }
  if (
    s.includes("maximum") ||
    s.includes("minimum") ||
    s.includes("number of ways") ||
    s.includes("optimal") ||
    s.includes("overlapping subproblems")
  ) {
    return "dynamic programming";
  }
  if (s.includes("sorted array") && (s.includes("find") || s.includes("search"))) {
    return "binary search";
  }
  if (s.includes("next greater") || s.includes("balanced parentheses") || s.includes("undo")) {
    return "stack";
  }
  if (s.includes("level order") || s.includes("minimum moves") || s.includes("shortest steps")) {
    return "queue / bfs";
  }
  if (s.includes("merge") && s.includes("interval")) {
    return "sorting + interval sweep";
  }
  if (s.includes("range sum") || s.includes("subarray sum equals")) {
    return "prefix sum (possibly + hash map)";
  }
  if (s.includes("disjoint") || s.includes("connected components with unions")) {
    return "union find (dsu)";
  }
  if (s.includes("prerequisite") || s.includes("dependency order")) {
    return "topological sort";
  }
  if (s.includes("linked list") && (s.includes("cycle") || s.includes("middle"))) {
    return "fast and slow pointers";
  }
  if (s.includes("choose") && s.includes("all combinations")) {
    return "backtracking";
  }
  if (s.includes("interval") || s.includes("schedule")) {
    return "greedy (possibly with sorting)";
  }

  return "review constraints and test candidates";
}
Extended rule-based pattern recognition helper

Sliding Window

Use it for contiguous ranges where you expand and shrink a window while tracking a condition.

maxSumWindow.ts
function maxSumWindow(nums: number[], k: number): number {
  let sum = 0;
  let best = -Infinity;

  for (let right = 0; right < nums.length; right++) {
    sum += nums[right];
    if (right >= k) sum -= nums[right - k];
    if (right >= k - 1) best = Math.max(best, sum);
  }

  return best;
}
Contiguous optimization with one pass

Two Pointers

Best when indices move from both sides with deterministic rules.

twoSumSorted.ts
function twoSumSorted(nums: number[], target: number): number[] {
  let left = 0;
  let right = nums.length - 1;

  while (left < right) {
    const sum = nums[left] + nums[right];
    if (sum === target) return [left, right];
    if (sum < target) left++;
    else right--;
  }

  return [];
}
Sorted pair search in O(n)

Hash Map

Choose a hash map for constant-time checks, frequency counts, or complement lookups.

containsDuplicate.ts
function containsDuplicate(nums: number[]): boolean {
  const seen = new Set<number>();
  for (const num of nums) {
    if (seen.has(num)) return true;
    seen.add(num);
  }
  return false;
}
Frequency/duplicate problems map naturally to sets/maps

Graph Traversal (BFS/DFS)

Use BFS for shortest path in unweighted graphs and DFS for exhaustive traversal/backtracking.

shortestPathUnweighted.ts
function shortestPathUnweighted(graph: number[][], start: number, target: number): number {
  const queue: [number, number][] = [[start, 0]];
  const seen = new Set<number>([start]);

  while (queue.length) {
    const [node, dist] = queue.shift() as [number, number];
    if (node === target) return dist;
    for (const next of graph[node]) {
      if (!seen.has(next)) {
        seen.add(next);
        queue.push([next, dist + 1]);
      }
    }
  }

  return -1;
}
BFS level-order gives shortest steps in unweighted graphs

Dynamic Programming

If subproblems repeat and choices build an optimal answer, store intermediate results.

climbStairs.ts
function climbStairs(n: number): number {
  if (n <= 2) return n;
  let a = 1;
  let b = 2;
  for (let i = 3; i <= n; i++) {
    const next = a + b;
    a = b;
    b = next;
  }
  return b;
}
DP turns repeated recursion into linear time
AlgoAnimator: Interactive Data Structures