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.
Start with cue extraction before writing any code.
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";
}Use it for contiguous ranges where you expand and shrink a window while tracking a condition.
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;
}Best when indices move from both sides with deterministic rules.
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 [];
}Choose a hash map for constant-time checks, frequency counts, or complement lookups.
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;
}Use BFS for shortest path in unweighted graphs and DFS for exhaustive traversal/backtracking.
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;
}If subproblems repeat and choices build an optimal answer, store intermediate results.
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;
}