Problem Statement

Permutation in String

You get two strings, s1 and s2. You want to know if some rearrangement of s1 shows up inside s2 as a connected chunk. A permutation just means the same letters in any order, so "ab" can be "ab" or "ba". A substring means a run of letters sitting next to each other, with nothing skipped. So the real question is: somewhere in s2, is there a stretch of letters that uses exactly the same letters as s1, just possibly shuffled? Return true if yes, false if no.

mediumSliding WindowSliding WindowTime: O(n) · Space: O(1)

Signals to notice

check if one string is a permutation of a substringthe same-size window keeps movingcharacter frequency match

Brute force first

Check every substring of s1's length in s2. It is a fair place to begin because it matches the surface of the question, yet it does not capture the deeper structure that makes the problem simpler.

The key insight

Slide a window of size len(s1) over s2, maintain frequency counts. Once you hold onto the right piece of information from moment to moment, the problem feels less like trial and error and more like following a shape that was there all along.

Trace it on s1="ab", s2="eidbaooo" (window size = 2)

count1 = {a:1, b:1}; window = Counter(s2[0:2]) = {e:1, i:1} -> != count1
i=2 (s2[2]='d'): add 'd', remove s2[0]='e' -> window={i:1, d:1} -> != count1
i=3 (s2[3]='b'): add 'b', remove s2[1]='i' -> window={d:1, b:1} -> != count1
i=4 (s2[4]='a'): add 'a', remove s2[2]='d' -> window={b:1, a:1} -> == count1 -> return True
Answer: true (window "ba" is a permutation of "ab")

What must stay true

A permutation exists when the window's character counts exactly match s1's counts. When you keep that truth intact, each local choice supports the larger solution instead of fighting it.

Shape of the loop

count1 = freq(s1); window = freq(s2[0:len(s1)])
if window == count1: return true
for i from len(s1) to len(s2)-1:
    window[s2[i]] += 1                 # slide right edge in
    window[s2[i-len(s1)]] -= 1         # drop left edge out (del if 0)
    if window == count1: return true
return false

Pseudocode only — the full worked solution lives in the Solution tab.

Easy way to go wrong

Comparing entire frequency maps each step — use a 'matches' counter for updates. Most mistakes here are not about syntax; they come from losing track of what your state, pointer, or structure is supposed to mean.

Sliding Window Pattern