Permutation in String: Fixed Window Frequency Matching
"Permutation in String" is a Medium-level staple in Microsoft, Google, Oracle loops, and it is a textbook fit for the Sliding Window pattern — one of the nine patterns that cover the bulk of what FAANG coding interviews actually test. Part 5 of 11 in the Sliding Window arc.
The Problem
Given strings s1 and s2, return True if s2 contains a permutation of s1 as a contiguous substring. Equivalently: does any window of s2 of length len(s1) have exactly the character counts of s1?
Input: s1 = "ab", s2 = "eidbaooo"
Output: True
The window "ba" is a permutation of "ab".
Recognizing the Sliding Window Pattern
Sliding window maintains a contiguous range over an array or string and slides its boundaries instead of recomputing from scratch. Fixed-size windows update a running aggregate in O(1) per step; variable-size windows grow the right edge and shrink the left only when a constraint breaks. Any problem asking about the best contiguous subarray or substring under a constraint should trigger this pattern.
A permutation constraint is a frequency-vector constraint, and the window size is fixed at len(s1) — so this is the fixed-size template where the aggregate is a character histogram instead of a sum.
The Approach
Build the target histogram and the first window's histogram over the 26 letters. Track matches — how many of the 26 counts agree. Each slide touches two letters, updating matches in O(1) per letter, so a full-histogram comparison never happens inside the loop.
The simpler compare-dicts-each-slide version is O(26·n) and still linear — offer the match-counter as the polish, and mention Python's Counter equality as the pragmatic baseline.
Python Solution
def check_inclusion(s1: str, s2: str) -> bool:
"""True if some window of s2 is a permutation of s1."""
n, m = len(s1), len(s2)
if n > m:
return False
A = ord("a")
need = [0] * 26
have = [0] * 26
for i in range(n):
need[ord(s1[i]) - A] += 1
have[ord(s2[i]) - A] += 1
matches = sum(1 for i in range(26) if need[i] == have[i])
if matches == 26:
return True
for right in range(n, m):
for idx, delta in ((ord(s2[right]) - A, 1), (ord(s2[right - n]) - A, -1)):
if have[idx] == need[idx]:
matches -= 1 # this letter was matched, will change
have[idx] += delta
if have[idx] == need[idx]:
matches += 1
if matches == 26:
return True
return False
Complexity
- Time: O(n + m) — constant work per slide via the match counter
- Space: O(1) — two 26-slot histograms and a counter
Interview Tips and Follow-Ups
- Guard
len(s1) > len(s2)first — skipping it crashes the seed loop and interviewers seed exactly that case. - Find All Anagrams (next in this arc) is this problem returning every matching start index instead of a boolean.
- If asked about Unicode, switch histograms to dicts and compare sizes lazily — say how the complexity changes.
More Sliding Window problems — and the other eight patterns — live in the Technical Interview category. Drill the pattern, not the problem: that is the entire thesis of this series.
Keep reading
Best Time to Buy and Sell Stock as a Window Problem
Max profit in one pass by tracking the running minimum buy price. Python solution and complexity analysis for the sliding window interview pattern.
Find All Anagrams in a String With One Sliding Histogram
Every anagram start index in one pass — the counting version of inclusion. Python solution and complexity analysis for the sliding window interview pattern.
Fruit Into Baskets: At Most Two Distinct, Decoded
Google's storytelling version of longest subarray with two distinct values. Python solution and complexity analysis for the sliding window interview pattern.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.