◀ THE GRIND — SLIDING WINDOW

Permutation In String

MEDIUM✓ CHIP-TIMEDLC #567 — FULL STATEMENT ↗

The drill: Somewhere inside the longer string there may be a contiguous block whose letters are exactly the first string, shuffled. Order can't identify such a block — only letter counts can, checked across every window of the right width.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

A short pattern string and a longer search string arrive together, and the question is whether some contiguous block of the search string is exactly a rearrangement of the pattern's letters.

Order inside that block never has to match the pattern's own order — only the multiset of letters and their counts need to line up exactly; position for position within the block doesn't matter.

The block, if one exists, must be exactly as wide as the pattern itself; wider or narrower stretches never qualify no matter what letters they contain.

EX 01
s1 = "ab" · s2 = "oobao"
true
THE SCRAMBLE SITS MID-STRING
EX 02
s1 = "ab" · s2 = "ooboo"
false
RIGHT LETTERS NEVER ADJACENT
EX 03
s1 = "abc" · s2 = "cba"
true
WHOLE HAYSTACK IS THE PERMUTATION
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

A permutation match ignores order entirely. What fingerprint of a block of text survives any shuffle of it?

HINT 2 THE STRUCTURE

Every candidate window has the same width as the pattern, so this is a fixed-size window over 26 letter counts — the question is how to avoid recounting per slide.

HINT 3 ONE STEP FROM THE ANSWER

Roll the window: one letter enters, one leaves, two count cells change. Track how many of the 26 cells agree with the pattern; a match is all 26 agreeing at once.

COACH'S BOARD — THE PATTERN, STEP BY STEP
ROLLING THE 26 COUNTSPATTERN · SLIDING WINDOW — FIXED WIDTHs1 = "ab" · s2 = "oobao"
o
o
b
a
o
LETTER TALLIES (need · have) · MATCHES
— empty —
STEP 1

Pattern "ab" needs one a and one b. Slide a width-2 window across "oobao" and count how many of the letter tallies agree.

STEP 1 / 5 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/permutation-in-string.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        m, n = len(s1), len(s2)
        if m > n:
            return False
        a = ord("a")
        need = [0] * 26
        have = [0] * 26
        for c in s1:
            need[ord(c) - a] += 1
        for c in s2[:m]:
            have[ord(c) - a] += 1
        matches = sum(1 for i in range(26) if need[i] == have[i])
        if matches == 26:
            return True
        for right in range(m, n):
            enter = ord(s2[right]) - a
            have[enter] += 1
            if have[enter] == need[enter]:
                matches += 1            # this cell just came into agreement
            elif have[enter] == need[enter] + 1:
                matches -= 1            # this cell just fell out of agreement
            leave = ord(s2[right - m]) - a
            have[leave] -= 1
            if have[leave] == need[leave]:
                matches += 1
            elif have[leave] == need[leave] - 1:
                matches -= 1
            if matches == 26:
                return True
        return False
TIME O(N)SPACE O(26)PYTHON · RACE PACE · 31 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED