Skip to main content

Command Palette

Search for a command to run...

How to Build Algorithmic Intuition for Coding Interviews

Volume builds memory of specific problems. Recognition is a different skill, and most prep methods skip it.

Published
9 min read
How to Build Algorithmic Intuition for Coding Interviews

You've solved more than 500 LeetCode problems. The easys take ten minutes. The mediums you've seen variations of take twenty. Then a medium lands in a phone screen that doesn't look like anything in your practice list, and you stall before you've decided what kind of problem it is. The instinct says solve more problems. The instinct is wrong.

Key takeaways

  • Volume practice is good at one thing: memory of specific problems. It's bad at the skill that decides which technique applies to a problem you haven't seen.

  • Learning research distinguishes near transfer (familiar problems) from far transfer (unfamiliar ones). Volume builds the first. Interviews test the second.

  • Recognition can be trained directly. Read the problem for features, name the technique, then code. The features are stable across many problems.

  • Conditions matter as much as content. The default LeetCode loop is friendlier than the interview. If your reads have always been informed by the tag, the moment the tag disappears, the read gets harder.

Worth flagging: I built Codeintuition, a structured learning platform for coding interviews. This post is about why the recognition skill stalls past a certain problem count, not about the product. The closing link goes to the longer version on my own blog.

What grinding is actually building

Volume practice has a real return. After a few hundred problems, you've stopped being confused by syntax, you've stopped misreading constraints, and the interview minutes that used to go to typo-hunting now go to the actual problem. That's earned. The trouble is what most people assume volume builds beyond that point.

The assumption is that with enough reps, the recognition skill emerges on its own. The brain notices the shapes of problems and starts grouping them. Sometimes it does. For a meaningful chunk of engineers, it doesn't, and the cause is structural. The default practice loop trains around recognition rather than at it.

Here's the loop. You attempt a problem. You get stuck. You glance at the LeetCode tag, you see sliding window, and you read a solution. The solution explains the implementation. The explanation rarely explains why this problem is the kind of problem that takes a sliding window. So the next time a sliding window problem shows up, you might recognise it from the surface details. The time after, when the surface details are different, you might not. Recognition is being built by accident.

In an interview, the tag is gone. The problem statement isn't labelled. So the skill that's been built by accident has to do work it was never explicitly trained for, and that's where the freeze comes from.

Near transfer vs far transfer

The learning sciences have a useful piece of language for this.

Near transfer is when you can solve a problem because it resembles one you've practised. You solved Maximum Sum Subarray of Size K. The interviewer asks you Maximum Sum Subarray of Size 3. The numbers changed but the underlying shape is identical, and recognition fires without any work.

Far transfer is when you can solve a problem that doesn't resemble anything in your practice set, by reading the structure of the problem and constructing the approach from first principles. You've never seen Longest Substring with At Most K Distinct Characters before. You read the problem and notice three things: it's a contiguous substring, the condition is a count of distinct characters, and the goal is to maximise the substring's length. Three observable features point at variable sliding window, even though the problem doesn't look like anything you've practised.

Volume practice mostly trains near transfer. Whether far transfer is reliably teachable is a debate the research on transfer of learning hasn't fully settled, but the evidence does support one specific intervention: explicit instruction in when and why a method applies, not just how to execute it, produces more transfer than practice alone.

A worked example: variable sliding window on K distinct characters

The problem: given a string s and an integer k, find the length of the longest substring of s that contains at most k distinct characters.

If you've seen this problem before, the temptation is to cycle through everything you remember about sliding windows until something fits. If recognition is trained, the read is short. Three observable features in the problem statement:

  1. The answer is a contiguous range. "Substring" rules out subsequence patterns and rules out reordering. The window has to be in the original sequence, in original order.

  2. There's a condition that holds across the window's contents. "At most k distinct characters" is checkable as the window grows or shrinks.

  3. The optimisation target is the window's length. "Longest" means we want the window as wide as possible while the condition still holds.

When all three are present, the technique is variable sliding window: expand the right edge greedily, contract the left edge whenever the condition breaks, and track the best length seen.

def longest_with_k_distinct(s, k):
    counts = {}
    left = 0
    best = 0
    for right, ch in enumerate(s):
        counts[ch] = counts.get(ch, 0) + 1
        while len(counts) > k:
            counts[s[left]] -= 1
            if counts[s[left]] == 0:
                del counts[s[left]]
            left += 1
        best = max(best, right - left + 1)
    return best

The implementation is short. The hard part is noticing that "contiguous range" and "condition on the window" and "optimise length" together name a single technique. Once they do, the implementation lifts directly from any other variable sliding window problem you've solved. That's far transfer in action.

A second worked example: longest substring without repeating characters

Same template, slightly different condition. The features:

  1. Contiguous range: substring, in original order.

  2. Condition across the window: no character appears twice.

  3. Optimisation target: maximum length.

The "no character appears twice" condition is checkable using a set: add the right character, contract from the left while the right character is already in the set. The window's contents are always unique, so the maximum length is the max width seen.

The features fire identically. The condition's implementation differs by one line. That's the kind of transfer the recognition drill is designed to produce.

What the drill looks like in practice

Before solving a new problem, run a 30 to 60 second pass on the statement alone. No code. The output of the pass is a name: which technique, and why.

For each technique you've learned, you should be able to write down the two or three observable features that signal it applies. A small set:

  • Variable sliding window: contiguous range, condition across window contents, optimisation on window length.

  • Two pointers: sorted array (or one you can sort), search for a pair or triple satisfying a target, pointers move from the ends inward.

  • Monotonic stack: per element answer, directional search left or right, comparison condition. Stock span fits. Next greater element fits.

  • Backtracking: enumerate combinations or paths under a constraint, with the option to abandon a partial candidate.

When you start a problem, read the constraints, list the features you see, name the technique, then start coding. If you can't name a technique in 60 seconds, you don't start coding. You re-read the constraints with your feature checklists open and try again. If you still can't, mark the problem and learn the missing feature before moving on.

The first time, this feels artificial. After 30 problems, the features start firing automatically as you read.

Practice conditions matter too

The recognition drill works against the variable sliding window lesson on Codeintuition or against any problem bank. What it can't fix on its own is the gap between practice conditions and interview conditions.

The default LeetCode loop has the title visible, the difficulty visible, the company tags visible, the discussion section a click away, and no clock. None of those are present in the actual interview. A useful practice protocol for the last few weeks before an interview cycle:

  • Cover the problem name before reading the constraints. Many problem names give away the technique.

  • Set a 25 minute clock per medium. If you blow past it, the problem went to "still working" rather than "solved", and the next pass focuses on what slowed you down.

  • Skip the discussion section on the first attempt. Read it after, only if your attempt didn't converge.

  • Mix techniques. Three sliding window problems in a row train nothing about recognition because the third is obvious by inertia. Three from different techniques force you to read the constraints.

This is a practice protocol, not a product. It runs against whatever problem bank you already use.

When grinding is actually the right call

Volume is the right move in two cases. When your fundamentals on a specific data structure are weak enough that you can't implement it cleanly even with the technique handed to you, more reps fix the bottleneck directly. When you're a few weeks out from a cycle and the goal is speed, the features you've already internalised get faster with reps.

The cases where volume stops working are different. When implementation is solid but recognition under unfamiliar problems is the bottleneck, more reps don't move the needle because they aren't training what's broken.

What the next problem looks like

Six months out, you open an unfamiliar problem. "Given a string of letters, return the length of the longest run where any rearrangement contains at most two distinct values within any window of length five." Nothing in your practice list looks like it.

Reading for features gets you somewhere. "Longest run" is contiguous and length-optimised. "At most two distinct values" is a condition across a window. "Within any window of length five" is the window-size constraint. The features pile up to a windowed problem with a nested condition. You start writing before the timer hits the three minute mark.

That's a trained skill. Volume helped earlier in the prep arc. Recognition is what closed the gap on novel problems.

Originally posted, with the per technique feature checklists for six more techniques, on my own blog.

When did the features of one of these techniques finally click for you, and which problem was it that broke it open?