</> MAANG.io
coding interview Β· 101

Foundations

Master coding interviews with comprehensive coverage of data structures, algorithms, and problem-solving techniques. Progress from fundamentals to advanced topics with expertly curated content.

0/255 solved 0% complete

The Substring-Matching Template

What is this?

Think of the window as a spotlight that can both widen and narrow. You first stretch its right edge outward until it covers everything you need, then squeeze its left edge inward to trim away anything wasteful β€” keeping the best window you have seen along the way. This one breathing motion, expand then contract, solves a surprising number of "find the smallest or longest stretch" problems with the same short piece of code.

flowchart TD A["Start with an empty window"] --> B["Expand the right edge until valid"] B --> C["Shrink the left edge while still valid"] C --> D["Record the best window seen"] D --> B

πŸ’‘ Fun fact: This expand-then-contract template is the same shape behind real-time search-and-highlight features and DNA motif scanners in bioinformatics, which hunt for the shortest stretch of a genome containing a given set of markers.

πŸ”“ The 2 problems in this chapter are free. Sign in with Google or Microsoft to start solving.


Core idea: Almost every hard sliding-window problem fits one template: grow the window on the right until it satisfies a condition, then shrink it from the left while it stays satisfied, recording the best as you go. Learn this ~10-line shape once and Minimum Window Substring, Longest Substring Without Repeating, and their cousins all become fill-in-the-blanks.


The template

need = Counter(t)          # what the window must contain (problem-specific)
have, required = 0, len(need)
left = 0
for right, ch in enumerate(s):
    # 1) include s[right] in the window state
    if ch in need:
        need[ch] -= 1
        if need[ch] == 0: have += 1
    # 2) while the window is VALID, try to shrink and record the answer
    while have == required:
        update_answer(left, right)
        lch = s[left]
        if lch in need:
            if need[lch] == 0: have -= 1
            need[lch] += 1
        left += 1

Only three things change per problem: what state the window tracks, what "valid" means, and whether you record on growth (longest) or on shrink (shortest).


The problems

Expand-to-valid, contract-to-optimal branches into Minimum Window Substring (smallest covering t) and Longest Substring Without Repeating (no duplicates)

  • Minimum Window Substring β€” the template at full strength: a need/have counter finds the smallest window containing all of t.
  • Longest Substring Without Repeating Characters β€” the validity is "no duplicate"; the last-seen-index trick jumps the left edge in O(1).

Key takeaways

  • One template: expand right to validity, contract left to optimality, record as you go.
  • Customize three things: the window state, the validity test, and record-on-grow vs record-on-shrink.
  • A required/formed counter makes validity O(1).
  • Last-seen-index lets "no repeats" jump the left edge instead of stepping.
  • Why interviewers love it: recognizing that a new problem is this template is the senior move.

Start here: Minimum Window Substring (the full template), then Longest Substring Without Repeating Characters.

Core idea: grow a window on the right until it becomes valid (it finally contains every required character with the right multiplicity), then shrink it on the left while it stays valid to make it minimal. Expand to become valid, contract to become minimal β€” and repeat. A single integer "how many required characters are fully satisfied" lets you test validity in O(1) instead of re-comparing two maps every step.

This is the lesson the whole chapter has been building toward. Fixed windows taught you to slide; the rolling dictionary taught you to track contents incrementally. Minimum Window Substring fuses both into the canonical variable-window template β€” the one that, once internalized, you reuse for a dozen "smallest/longest substring satisfying a constraint" problems.

Problem, rephrased

You're given two strings, s (the haystack) and t (the requirement). Return the shortest contiguous substring of s that contains all the characters of t, counting multiplicities β€” if t = "aab" your window must hold at least two as and one b. If no such window exists, return the empty string "".

Picture a stretchy bracket [left … right] laid over s. You drag right forward to collect characters until your bracket holds everything t demands. The instant it's satisfied, you stop adding and start pulling left inward, dropping characters from the front as long as the bracket stays satisfied β€” squeezing out slack. Each time the bracket is valid you note its width; the narrowest one you ever saw is the answer.

s t Smallest covering window Output
"ADOBECODEBANC" "ABC" …BANC at the end "BANC"
"a" "a" the whole thing "a"
"a" "aa" needs two as, only one exists ""
"aa" "aa" exact match, counts matter "aa"
"cabwefgewcwaefgcf" "cae" cwae "cwae"

Notice row 3: multiplicities are real. One a does not satisfy a requirement for two β€” that window never becomes valid, so the answer is "".

Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account β€” no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.