If you have ever stared at a "Medium" LeetCode problem involving arrays or strings and felt like you needed a nested loop, you are not alone. The brute force approach is natural. But it is also slow—usually .
The Sliding Window pattern is the technique that transforms that slow brute force into a blazing fast solution. It is not just an algorithm; it is a way of thinking about data as a fluid stream rather than a static block.
In this guide, we will build your sliding window intuition from the ground up. You will learn the difference between fixed and dynamic windows, master the "grow until invalid, then shrink" mental model, and walk through real examples step-by-step.
TL;DR — The Sliding Window Algorithm:
- Initialize
left = 0. - Loop
rightfrom0ton. - Add
nums[right]to window. whilewindow is invalid: removenums[left], incrementleft.- Update max/min result.
What is sliding window?
At its core, a Sliding Window is a sub-list that runs over an underlying collection. Instead of re-calculating the entire subarray every time we move one step, we reuse the result from the previous step.
Think of it like a window frame sliding over a long strip of paper. You can only see a portion of the paper at a time. As you slide the frame to the right, one new character enters the view, and one old character leaves.
This technique is a specific variation of the Two Pointers pattern, where both pointers move in the same direction to define a range [left, right].
Fixed‐size vs dynamic window: visual comparison
There are two distinct flavors of this pattern, and mixing them up is a common source of bugs.
1. Fixed-Size Window
The window size never changes. You slide it one element at a time.
- Use case: "Find the maximum sum of any contiguous subarray of size 3."
- Movement:
rightincrements by 1,leftincrements by 1. They are locked together.
2. Dynamic-Size Window
The window grows and shrinks like a caterpillar based on a condition.
- Use case: "Find the longest substring without repeating characters."
- Movement:
rightincrements to grow.leftincrements only when the window becomes invalid (to shrink it).
This guide focuses on the Dynamic Window, as it is the one that trips up most candidates.
Walkthrough Example #1: Longest Substring Without Repeating Characters
Let's solve the classic problem: Given string s = "abcabcbb", find the length of the longest substring without repeating characters.
We use a Hash Set to track characters in our current window.
Step 1: Expand the right pointer
We start with left = 0 and right = 0.
We move right forward, adding characters to our set.
- Add 'a'. Window:
"a". Valid. - Add 'b'. Window:
"ab". Valid. - Add 'c'. Window:
"abc". Valid.
Step 2: Shrink the left pointer
Now right points to the second 'a'.
- We try to add 'a'. Duplicate found! The window
"abca"is invalid.
This is the crucial moment. We cannot expand further. We must shrink from the left until the window is valid again.
- Remove
s[left]('a') from the set. - Increment
left. - New Window:
"bca". Valid? Yes.
Now we can resume expanding right.
function lengthOfLongestSubstring(s: string): number {
let left = 0;
let maxLength = 0;
const charSet = new Set<string>();
for (let right = 0; right < s.length; right++) {
// Shrink the window if adding s[right] creates a duplicate
while (charSet.has(s[right])) {
charSet.delete(s[left]);
left++;
}
// Expand the window
charSet.add(s[right]);
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}Walkthrough Example #2: Subarray Sum ≤ K
Let's look at a slightly different constraint: "Find the length of the longest subarray with sum ." (Assume positive numbers).
- Expand: Add numbers to
currentSum. - Condition: Is
currentSum > K? - Shrink: If yes, subtract
nums[left]and moveleftforward untilcurrentSum <= K.
Notice the pattern? The logic is identical. The only thing that changes is the condition for shrinking.
Key mental model: “grow until invalid, then shrink”
If you remember only one thing from this article, make it this loop:
- Grow: Increase
rightto include a new element. - Check: Does adding this element break the rule? (e.g., duplicate char, sum too large).
- Shrink: If the rule is broken, increase
leftto remove elements until the rule is satisfied again. - Update: Update your global maximum (or minimum) with the current valid window size.
This "caterpillar" movement ensures we check every possible valid window without redundant checks.
Warning: This logic relies on the problem being "monotonic." If adding an element doesn't consistently increase the "cost", this breaks. See our guide on When NOT to Use Sliding Window for those edge cases.
Common misconceptions
Misconception 1: "The window only grows."
Beginners often forget the while loop for shrinking. They use an if statement instead.
- Correction: You might need to remove multiple elements from the left to make the window valid again. Always use
while.
Misconception 2: "We shrink first."
Usually, we expand first to see if we can make a bigger window. We only shrink when forced to.
- Correction: The standard template is
for (right) { expand; while (invalid) shrink; update; }.
Tips for building intuition
- Use your hands: Literally use your index fingers as pointers on a piece of paper. Move the right one. When you hit a "bad" state, move the left one.
- Dry run with a table: Write columns for
left,right,window_content, andcondition_value. Fill it out row by row. - Practice with Visualizers: Tools like LeetCopilot's Study Mode can help you visualize these patterns interactively, highlighting exactly when the window shifts.
FAQ
Q: Why is this O(N) if there is a loop inside a loop?
A: Great observation. Although there is a while loop inside the for loop, the left pointer only moves forward. It never moves back. In the worst case, left visits each element once and right visits each element once. Total operations = , which is .
Q: How do I know if it's a sliding window problem?
A: Look for keywords like "longest", "shortest", "contiguous subarray", or "substring". If the problem asks for a range that satisfies a condition, it's a strong candidate.
Q: Does this work for "Subarray Sum Equals K"?
A: No! If the array has negative numbers, the "grow until invalid" logic fails. You need Prefix Sums for that.
Summary and where to go next
Sliding Window is about managing a dynamic range. It is efficient because it avoids re-doing work. By mastering the expansion and shrinking logic, you can solve dozens of "Medium" and "Hard" string/array problems.
Next Steps:
- Read When NOT to Use Sliding Window to avoid common traps.
- Practice "Longest Substring Without Repeating Characters" on LeetCode.
- Try "Minimum Size Subarray Sum" to practice the "shortest" window variant.
- Check out our Sliding Window Template for Strings for a deep dive into string problems.
Ready to Practice This Pattern?
Apply this pattern with LeetCopilot's AI-powered hints, notes, and mock interviews. Transform your coding interview preparation today.
