Hello! Welcome back.
In our last lesson, we laid the groundwork for the variable-size sliding window, learning the core templates for finding the "longest" and "shortest" substrings that meet certain criteria. We saw how a hash map could be used to maintain the window's state.
Today, we're going to do a deep dive into that specific combination: the sliding window powered by a frequency map. This duo is one of the most effective patterns for solving a wide variety of substring problems in FAANG interviews. Your experience with key-value stores and state management in backend development will give you a great intuition for how these frequency maps operate as the "brain" of our sliding window.
Our goal today is to master this pattern by applying it to several classic LeetCode problems, moving from a simple warm-up to more complex variations. By the end of this lesson, you'll be able to confidently solve substring problems using a sliding window and a frequency map.
1. Warm-up: Longest Substring Without Repeating Characters
Let's start with a foundational problem: LeetCode 3, "Longest Substring Without Repeating Characters". This is a "find the longest" problem, so the template we learned in the previous lesson applies directly.
The condition is "without repeating characters." The most natural data structure to track this is a Set, which you can think of as a simplified frequency map where we only care if a character exists, not how many times.
To see how this works, let's watch a clear and concise explanation.
Longest Substring Without Repeating Characters - Leetcode 3 - Python
This video from NeetCode walks through the problem, illustrating how a sliding window combined with a set provides an elegant and efficient O(n) solution.
Please watch from 01:16 to the end (06:43). Pay close attention to the logic: when a duplicate is found, the window shrinks from the left until it's valid again. The code walkthrough at the end consolidates the algorithm.
Let's break down the logic using the "find maximum length" template:
- Initialize:
left = 0,maxLength = 0, and our window state,charSet = new Set(). - Expand Window: Iterate with a
rightpointer from the beginning to the end of the string. - Check Condition & Shrink: For the current character
s[right], if it's already in ourcharSet, our window is invalid. We must shrink it from the left until the duplicate is removed.while (charSet.has(s[right])) { charSet.delete(s[left]); left++; } - Process Current Element: After ensuring the window is valid, add the current character.
charSet.add(s[right]); - Update Result: The window is now valid and as large as it can be at this moment. We update our result.
maxLength = Math.max(maxLength, right - left + 1);
This elegant solution processes each character at most twice, once by the right pointer and once by the left, giving us the optimal O(n) time complexity.
2. Fixed-Size Window: Permutations and Anagrams
Now, let's explore a variation where the window size is fixed. This pattern is perfect for problems where you need to find a permutation or anagram of a smaller string (pattern) within a larger string (str).
Consider "Find All Anagrams in a String" (LeetCode 438). An anagram is just a permutation. This means we are looking for any substring in str that is exactly the length of pattern and contains the exact same characters with the same frequencies.
The core idea is:
- Create a frequency map for the
pattern. - Slide a window of size
pattern.lengthacrossstr. - For each window, check if its character frequencies match the
pattern's frequencies.
A naive approach would be to rebuild the frequency map for the window at every single position, which is inefficient. The sliding window allows us to do this much faster. As the window slides one position to the right, we simply add the new character's frequency and remove the frequency of the character that just left the window.
Pattern 01 : Sliding Window.md
This GitHub guide provides excellent, commented code for several sliding window problems. We'll look at the sections for 'Permutation in a String' and 'String Anagrams' to see this fixed-size window pattern in action.
Please read the sections titled 'Permutation in a String (hard)' and 'String Anagrams (hard)'. Notice how the logic is almost identical for both. Focus on how the frequency map is updated as the window slides and how the isMatch or matched variable cleverly avoids comparing the full hash maps at every step.
The Optimized Approach with a Match Counter
Instead of comparing two full frequency maps at every slide, we can use a counter. Here's the logic for finding all anagrams:
-
Initialization:
- Create
patternFreq, a map of character frequencies in thepattern. - Initialize
matched = 0. This will track how many characters from the pattern we have satisfied in our current window. - The number of unique characters in the pattern is our target, let's say
required = Object.keys(patternFreq).length.
- Create
-
Slide and Update:
- Iterate through the main string
strwith therightpointer. - Let
endChar = str[right]. IfendCharis inpatternFreq, decrement its count in the map. - If the count for
endCharbecomes0, it means we have the exact number of that character needed for an anagram, so we incrementmatched.
- Iterate through the main string
-
Check for Anagram:
- Once
matched === required, it means our current window might contain an anagram. We push the starting index (windowStart) to our results.
- Once
-
Shrink Window:
- When the window size (
right - left + 1) reaches thepattern.length, we must start shrinking it from the left to maintain the fixed size. - Let
startChar = str[left]. IfstartCharwas a required character (i.e., inpatternFreq):- If its frequency was
0before we put it back, it means we are about to lose a match, so we decrementmatched. - Increment its frequency in the map (putting it back).
- If its frequency was
- Finally, slide the window forward by incrementing
left.
- When the window size (
This technique is very efficient, as we are only performing simple arithmetic operations at each step, maintaining the O(N) time complexity where N is the length of the main string.
Test your understanding!
You are finding anagrams of pattern = "AB" in str = "BAC".patternFreq is { A: 1, B: 1 }. required = 2. matched = 0. left = 0.
The window is currently [B, A]. right = 1. Your frequency map for the window has { B: 0, A: 0 }, and matched = 2. You have just found an anagram at index 0.
What are the exact steps to process the next character, C, at right = 2?
Show answer
- Shrink First: The window
[B, A]is of size 2, which ispattern.length. Before expanding, we must shrink. The character leaving isstr[left], which is'B'.- The frequency of
'B'in our map was 0. We are losing a match, somatchedbecomes 1. - We put
'B'back into the map. The map now has{ B: 1, A: 0 }. - Increment
leftto 1. The window is now conceptually'A'.
- The frequency of
- Expand: Process
str[right], which is'C'.'C'is not inpatternFreq, so we do nothing to the map ormatched.
- Check for Anagram:
matchedis 1, which is not equal torequired(2). No anagram found. - The loop continues. The final window
[A, C]is not an anagram.
3. Deep Dive: Minimum Window Substring
Let's revisit the hard problem from our last lesson, "Minimum Window Substring" (LeetCode 76). This is the ultimate test of your understanding of variable-size windows and frequency maps. Mastering it is a huge step toward tackling FAANG-level medium/hard problems.
The problem asks for the smallest substring in s that contains all characters of t, including duplicates.

We use the "find minimum" template: expand until the condition is met, then shrink as much as possible while the condition holds. The complexity lies in efficiently tracking the condition: "does my window contain all characters of t?"
We'll use a new video resource for a fresh perspective and then a detailed article to truly cement the concepts.
Minimum Window Substring - LeetCode 76 - JavaScript
This AlgoJS video provides a step-by-step visual walkthrough of the algorithm in JavaScript, which should feel familiar to you. It clearly explains the 'expand' and 'shrink' phases and how two frequency maps are used.
Please watch from 01:20 to 13:49. The first part (up to 09:53) is a visual walkthrough of the logic. The second part is the JavaScript implementation. Focus on the roles of the count variable and the two maps.
To round out your understanding, we'll consult a detailed guide that covers not just the solution, but also how to think about it in an interview setting.
Minimum Window Substring: Variable-Size Sliding Window
This guide is a fantastic resource for interview preparation. It covers pattern recognition, the solution approach, common pitfalls, and edge cases for the Minimum Window Substring problem.
Please read these sections carefully: Pattern Recognition: Helps you identify when to use this pattern. Solution Approach: A step-by-step dry run of the logic. Common Pitfalls: Crucial for avoiding bugs under pressure. Edge Cases: Shows your thoroughness as an engineer. FAQs: Reinforces key concepts. Don't worry about the code snippets in different languages; focus on the explanatory text.
The core strategy for Minimum Window Substring is the two-map, two-counter approach:
needMap: A frequency map of the target stringt. This is static.windowMap: A frequency map of the current sliding window. This is dynamic.requiredCounter: The number of unique characters int.formedCounter: The number of unique characters in the current window that meet or exceed the required frequency int.
You expand the window until formed === required. Once met, you are in the shrinking phase, where you find the smallest possible window by moving the left pointer until formed < required.
Conclusion
Today, we've solidified your command of the sliding window pattern by focusing on its most powerful partner: the frequency map. You've seen how this combination can tackle a range of substring problems, from finding the longest substring with unique characters to finding permutations and even the notoriously tricky minimum window substring.
Key Takeaways:
- Frequency maps are the engine of the sliding window for substring problems. They efficiently track the state of the characters within the window.
- The
Setis a simple and effective frequency map for problems concerned only with character presence (e.g., "Longest Substring Without Repeating Characters"). - The fixed-size sliding window is a key sub-pattern for anagram and permutation problems. The "match counter" is a critical optimization to avoid comparing full maps.
- The two-map
have/need(orformed/required) counter technique is the standard, efficient solution for complex variable-size window problems like "Minimum Window Substring".
Preview of the Next Lesson:
We will continue exploring sliding window variations. Our next lesson will introduce a specialized data structure, the deque (double-ended queue), to solve another class of problems: finding the maximum or minimum in a fixed-size sliding window (e.g., "Sliding Window Maximum" - LeetCode 239). This will add another powerful tool to your problem-solving arsenal.