Cracking the Tech Interview

Cracking the Tech Interview

How to Recognize Coding Patterns Without Memorizing Questions

Memorizing questions trains you for questions you have already seen. Recognizing patterns trains you for questions nobody has shown you yet. Here is the difference, and how to build the second skill.

Rafay Abbasi's avatar
Rafay Abbasi
Jul 20, 2026
∙ Paid

There are two ways to prepare for coding interviews, and they feel almost identical from the outside but produce completely different results under pressure.

The first is memorization.

You study a problem, learn its solution, tag it, and move to the next. You build a catalog.

When the interview arrives, you scan the problem for something familiar and reach into the catalog.

If something matches, you win.

If nothing matches, you freeze.

The second is recognition. You study a problem not to remember its solution but to understand what made it want that solution. You learn the signals, the words, the structures, the constraints, that point toward a pattern.

When the interview arrives, you read the problem for those signals. You diagnose before you solve.

The problem does not need to match your catalog, because you are not looking for a match. You are looking for evidence.

The difference is not subtle.

Memorization scales linearly with the number of problems you have seen.

Recognition scales with the number of patterns you understand, which is a much smaller number that covers a much larger space.

Someone who has memorized three hundred problems is still helpless on problem three hundred and one.

Someone who has built genuine recognition across a dozen patterns walks into every problem with a method.

This post explains how recognition actually works and how to build it deliberately.

What Is Recognition

Recognition is not a feel for problems that some people have and others do not. It is a learned skill built from a set of specific, observable inputs.

Problems are not random. They are constrained by what makes them computable and interesting, which means they leak their pattern through a small number of channels.

Learn to read those channels and the problem tells you what it wants.

There are four primary channels through which a problem signals its pattern.

The words it uses: Problems are written with specific vocabulary, and that vocabulary is not accidental.

“Contiguous subarray” or “substring” almost always means sliding window.

“Sorted array” paired with “find a pair or value” almost always means two pointers or binary search.

“Top K,” “K closest,” or “K most frequent” almost always means a heap.

“All combinations,” “all subsets,” “all permutations,” the word “all” next to a generating task, almost always means backtracking.

“Shortest path” or “fewest steps” in an unweighted graph almost always means BFS. These are not coincidences. They are the fingerprints of the underlying structure, and problem-setters use them because they are the natural way to describe what a pattern does.

The shape of the output: What kind of answer does the problem want? This single question eliminates half the patterns before you have thought about anything else.

A problem asking for a single number (maximum, minimum, count, sum) points toward DP or a simple scan.

A problem asking for a list of all possibilities (all combinations, every valid path, every permutation) almost certainly means backtracking.

A problem asking for a yes/no boolean points toward search or cycle detection.

A problem asking for a specific element (the Kth largest, the closest point) points toward a heap or sorting. Read the output shape before anything else.

The constraints: The size limits in a problem are hints in disguise, and ignoring them is one of the most common ways candidates leave points on the table.

A constraint of n up to twenty quietly permits exponential time, which is a signal that a backtracking or brute-force recursive solution is acceptable and possibly expected.

A constraint of n up to a hundred thousand rules out anything slower than O(n log n) and points toward sorting, binary search, or a single-pass technique.

A constraint of n up to ten to the ninth almost always means O(1) or O(log n), a mathematical formula or binary search. Read the constraints, compute what complexity fits, and let that boundary tell you which patterns are in play.

The structure of the input: What does the data look like?

A sorted array has properties you can exploit.

A graph implies traversal.

A tree implies recursion or level-by-level processing.

Two strings together almost always mean something about comparing characters or building a common structure. A grid implies treating cells as nodes.

The structure of the input gives you the structure of the solution, because the solution has to match its shape to the data it processes.

These four channels together, words, output shape, constraints, and input structure, are usually enough to narrow a problem to one or two patterns before you have designed anything.

The ninety seconds you spend reading for these signals is the most valuable ninety seconds in the interview.

Knowing these channels is not the same as being able to apply them automatically under pressure.

Recognition is a motor skill as much as a cognitive one, it has to be practiced until it is fast and reflexive, which requires a specific kind of practice that most people skip.

Name the pattern before you touch the problem.

Every time you sit down with a problem, force yourself to spend the first sixty to ninety seconds reading for the four channels and stating your hypothesis out loud: “The input is sorted, the output is a pair, so I think this is two pointers.”

Then start. This discipline is the single most important habit to build, and it is also the exact behavior interviewers want to see, because it makes your reasoning visible.

Candidates who code in silence look like they are guessing.

Candidates who diagnose out loud look like they are thinking.

Practice on problems grouped by pattern, then deliberately randomize.

Pattern-grouped practice (all sliding window problems, then all DP, then all graph problems) builds the ability to apply each pattern. But it does not build recognition, because you already know the answer before reading the problem.

Once you have worked through a pattern’s problems, reshuffle them randomly and practice the diagnosis step cold, reading each problem and naming the pattern before you look at which category it belongs to. This is the specific practice that closes the gap between “I can solve this when I know the pattern” and “I can figure out the pattern from nothing.”

Notice what fooled you.

When your diagnosis is wrong, the failure is information. Maybe you saw “sorted array” and reached for two pointers, but the actual pattern was binary search (output shape was a single boundary, not a pair).

Write down exactly which signal misled you and which signal you missed. These notes are the most valuable part of the practice, because they are a personalized map of your pattern-blindness, and addressing them specifically is far more efficient than generic grinding.

Use the constraint check as a forcing function.

Before committing to any approach, ask “does this fit the constraints?”

If your solution is O(n squared) and n can be a million, your diagnosis was wrong or your optimization is incomplete. This constraint sanity check catches misidentified patterns before you have written any code, which is exactly when the feedback is most useful.

The Disambiguation Layer

Sometimes the four channels point toward two plausible patterns, and you need a tiebreaker.

Here is how to resolve the most common ambiguities.

Sorted input, find a pair: two pointers or binary search?

The output shape resolves this.

If you need to find a single value or boundary, binary search.

If you need a pair that satisfies some relationship (sum to target, smallest difference), two pointers converging from both ends.

Two pointers also applies when the problem asks you to partition the array or compare elements from opposite ends.

python

# Two pointers: pair that sums to target in a sorted array
def two_sum_sorted(a, target):
    l, r = 0, len(a) - 1
    while l < r:
        s = a[l] + a[r]
        if s == target: return [l, r]
        if s < target: l += 1
        else: r -= 1
    return None

Pair problem, unsorted input: hash map, not two pointers.

User's avatar

Continue reading this post for free, courtesy of Rafay Abbasi.

Or purchase a paid subscription.
© 2026 DG Learning · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture