Sliding Window Algorithm Explained: Master Array Problems for Coding Interviews
Complete guide to sliding window technique in Python. Learn how to solve LeetCode substring and subarray problems in O(n) time with 2 proven patterns. Master fixed and variable window approaches with real interview examples

The "Aha!" Moment That Changed How I Solve Array Problems
I'll never forget the first time I encountered a "longest substring" problem in an interview. My immediate instinct was to use nested loopsâcheck every substring, compare their properties, keep track of the longest one. It worked, but the interviewer's expression told me everything: "Can you do better?"
That's when I learned about the sliding window technique, and it genuinely felt like discovering a superpower. Suddenly, problems that seemed to require O(n²) nested loops could be solved in a single O(n) pass. The trick? Instead of recomputing everything from scratch for each position, maintain a "window" that slides across your data structure, updating only what changes.
In this guide, I'll share everything I wish someone had told me about the sliding window technique when I started. No fancy theoryâjust practical patterns, clear examples, and the intuition you need to recognize when to use this powerful approach.
What Makes Sliding Window So Powerful?
Before diving into patterns, let's understand why this technique is such a game-changer. Consider this simple problem: Find the maximum sum of any subarray of size 3 in the array [2, 1, 5, 1, 3, 2].
The brute force approach:
# Check every possible subarray of size 3
max_sum = 0
for i in range(len(arr) - 2):
current_sum = arr[i] + arr[i+1] + arr[i+2]
max_sum = max(max_sum, current_sum)
This works, but notice the redundancy. When we move from position 0 to position 1, we're recalculating sums that share two elements:
- Position 0:
[2, 1, 5]â sum = 8 - Position 1:
[1, 5, 1]â sum = 7
We're adding 1, 5, and 1 again, even though we already added 1 and 5 in the previous iteration!
The sliding window approach:
# Calculate first window
window_sum = sum(arr[:3]) # 2 + 1 + 5 = 8
max_sum = window_sum
# Slide: remove left element, add right element
for i in range(3, len(arr)):
window_sum = window_sum - arr[i-3] + arr[i]
max_sum = max(max_sum, window_sum)
See the difference? Instead of summing 3 elements repeatedly, we subtract one and add one. This simple optimization transforms O(n Ă k) into O(n), where k is the window size.
The Two Window Patterns You Must Master
Through solving dozens of sliding window problems, I've identified that virtually all of them fall into two categories. Master these two patterns, and you'll recognize the solution to 95% of sliding window problems within seconds.
Pattern 1: Fixed-Size Window
When to recognize:
- Problem explicitly gives you a window size (K, or "subarray of length...")
- Asked to find something in "every window of size K"
- Terms like "maximum sum of subarray of size K" or "first negative in every window"
The template:
def fixed_window_template(arr, k):
"""
Template for fixed-size sliding window problems.
Window size remains constant, slide by moving both pointers.
"""
# Step 1: Calculate initial window
window_state = calculate_window(arr[:k])
result = process_window(window_state)
# Step 2: Slide window
for i in range(k, len(arr)):
# Remove leftmost element from window
remove_element(arr[i - k], window_state)
# Add rightmost element to window
add_element(arr[i], window_state)
# Process current window
result = update_result(window_state, result)
return result
Mental model: Imagine a physical window frame sliding across an array. The frame size never changesâyou're just shifting it one position at a time, updating what's visible through the frame.
Pattern 2: Variable-Size Window
When to recognize:
- Problem asks for "longest" or "shortest" substring/subarray satisfying a condition
- No explicit window size given
- Conditions like "at most K distinct characters" or "without repeating characters"
- Terms like "minimum window" or "maximum length"
The template:
def variable_window_template(arr):
"""
Template for variable-size sliding window problems.
Window expands/contracts based on conditions.
"""
left = 0
window_state = initialize()
result = None
# Expand window by moving right pointer
for right in range(len(arr)):
# Add current element to window
add_element(arr[right], window_state)
# Contract window while condition is violated
while condition_violated(window_state):
remove_element(arr[left], window_state)
left += 1
# Update result with current valid window
result = update_result(right - left + 1, result)
return result
Mental model: Think of an accordion or rubber band. You're constantly trying to expand it (move right pointer) to explore more elements, but when it violates a condition, you contract it (move left pointer) until it's valid again.
Fixed-Size Window: Practical Examples
Let me walk you through three progressively challenging fixed-window problems to build your intuition.
Example 1: Maximum Sum Subarray of Size K
LeetCode #643 - Maximum Average Subarray I
This is the "hello world" of sliding windowsâthe problem I showed earlier.
def max_sum_subarray(arr, k):
"""
Find maximum sum of any subarray of size k.
Classic fixed-size window pattern.
"""
if k > len(arr) or k <= 0:
return 0
# Calculate sum of first window
window_sum = sum(arr[:k])
max_sum = window_sum
# Slide window: subtract left element, add right element
for i in range(k, len(arr)):
window_sum = window_sum - arr[i - k] + arr[i]
max_sum = max(max_sum, window_sum)
return max_sum
Test cases:
max_sum_subarray([1, 4, 2, 10, 23, 3, 1, 0, 20], 4)â 39 (10+23+3+1)max_sum_subarray([2, 3, 5, 1, 6], 2)â 8 (1+6 is incorrect, should be 7 at 1+6)
Key insight: We maintain only one piece of state (window_sum) that updates incrementally. This is the essence of sliding windowâincremental updates instead of full recalculations.
Example 2: First Negative Number in Every Window
This problem introduces a new concept: maintaining a queue of relevant elements as the window slides.
Problem: Given an array and window size K, find the first negative number in each window. If no negative exists, return 0.
from collections import deque
def first_negative_in_windows(arr, k):
"""
Find first negative in each window using deque.
Deque stores indices of negative numbers in current window.
"""
result = []
negatives = deque() # Store indices of negative numbers
for i in range(len(arr)):
# Add current element's index if negative
if arr[i] < 0:
negatives.append(i)
# Window is complete (has k elements)
if i >= k - 1:
# Remove indices outside current window
while negatives and negatives[0] <= i - k:
negatives.popleft()
# First element in deque is first negative in window
if negatives:
result.append(arr[negatives[0]])
else:
result.append(0)
return result
Test case:
first_negative_in_windows([12, -1, -7, 8, -15, 30, 16, 28], 3)- Output:
[-1, -1, -7, -15, -15, 0]
Key insight: Sometimes we need to maintain additional state about elements in the window. A deque (double-ended queue) is perfect for tracking relevant elements because we can efficiently add to the back and remove from the front as the window slides.
Example 3: Count Occurrences of Anagrams
This problem tests whether you can track more complex state (character frequencies) in a sliding window.
Problem: Given a text and a pattern, count how many anagrams of the pattern exist as substrings in the text.
from collections import Counter
def count_anagrams(text, pattern):
"""
Count occurrences of pattern's anagrams in text.
Uses character frequency map in fixed-size window.
"""
k = len(pattern)
pattern_count = Counter(pattern)
window_count = Counter()
matches = 0
count = 0
for i in range(len(text)):
# Add current character to window
window_count[text[i]] += 1
# Track how many characters match pattern frequencies
if text[i] in pattern_count and window_count[text[i]] == pattern_count[text[i]]:
matches += 1
# Window is complete
if i >= k - 1:
# Check if all characters match (found anagram)
if matches == len(pattern_count):
count += 1
# Remove leftmost character from window
left_char = text[i - k + 1]
if left_char in pattern_count and window_count[left_char] == pattern_count[left_char]:
matches -= 1
window_count[left_char] -= 1
if window_count[left_char] == 0:
del window_count[left_char]
return count
Test case:
count_anagrams("forxxorfxdofr", "for")â 3- The anagrams are: "for", "orf", "ofr"
Key insight: For complex conditions, maintain detailed state (like frequency maps) that updates as the window slides. The pattern is the sameâjust the state management is more sophisticated.
Variable-Size Window: The Real Challenge
Variable-size windows are where sliding window technique truly shines and where most interview problems lie. The key difference: your window size dynamically adjusts based on conditions.
Example 4: Longest Substring Without Repeating Characters
LeetCode #3 - Longest Substring Without Repeating Characters
This is probably the most famous sliding window problem and a fantastic example of the variable-size pattern.
Problem: Find the length of the longest substring without repeating characters.
def longest_unique_substring(s):
"""
Find longest substring with all unique characters.
Expand window, contract when duplicate found.
"""
char_set = set()
left = 0
max_length = 0
for right in range(len(s)):
# Expand: add current character
# But first, contract if it creates duplicate
while s[right] in char_set:
char_set.remove(s[left])
left += 1
# Add current character to window
char_set.add(s[right])
# Update maximum length
max_length = max(max_length, right - left + 1)
return max_length
Test cases:
longest_unique_substring("abcabcbb")â 3 ("abc")longest_unique_substring("bbbbb")â 1 ("b")longest_unique_substring("pwwkew")â 3 ("wke")
The pattern in action:
For "abcabcbb":
- Start:
left=0, right=0, window="a", valid â, length=1 right=1, window="ab", valid â, length=2right=2, window="abc", valid â, length=3right=3, window="abca", duplicate 'a'! Contract left- Contract: remove 'a', now window="bca", valid â, length=3
- Continue...
Key insight: The while loop is crucial. We contract the window (move left pointer) until the condition is satisfied again. This ensures we're always working with a valid window.
Example 5: Longest Substring With K Distinct Characters
This problem introduces a counting constraintâa very common pattern in interviews.
Problem: Find the length of the longest substring that contains at most K distinct characters.
from collections import defaultdict
def longest_k_distinct(s, k):
"""
Find longest substring with at most k distinct characters.
Track character frequencies in window.
"""
char_count = defaultdict(int)
left = 0
max_length = 0
for right in range(len(s)):
# Expand: add current character
char_count[s[right]] += 1
# Contract while we have too many distinct characters
while len(char_count) > k:
char_count[s[left]] -= 1
if char_count[s[left]] == 0:
del char_count[s[left]]
left += 1
# Update maximum length
max_length = max(max_length, right - left + 1)
return max_length
Test cases:
longest_k_distinct("aabacbebebe", 3)â 7 ("cbebebe")longest_k_distinct("aaaa", 2)â 4 ("aaaa")
Key insight: Using a frequency map (Counter or dict) allows us to track both what characters are in the window and their counts. We can then easily check conditions like "number of distinct characters."
Example 6: Minimum Window Substring (The Boss Level)
LeetCode #76 - Minimum Window Substring
This is considered a hard problem, but with the variable-size window pattern, it becomes manageable.
Problem: Find the minimum window in string S that contains all characters of string T.
from collections import Counter
def min_window_substring(s, t):
"""
Find smallest window in s containing all characters of t.
Expand to find valid window, contract to minimize it.
"""
if not s or not t:
return ""
# Frequency map of characters needed
needed = Counter(t)
window_counts = {}
# Track how many unique characters in t we've satisfied
have, need = 0, len(needed)
# Result: (window_length, left, right)
result = float('inf'), 0, 0
left = 0
for right in range(len(s)):
# Expand: add character from right
char = s[right]
window_counts[char] = window_counts.get(char, 0) + 1
# Check if this character's requirement is now met
if char in needed and window_counts[char] == needed[char]:
have += 1
# Contract: try to minimize window while maintaining validity
while have == need:
# Update result if this window is smaller
if (right - left + 1) < result[0]:
result = (right - left + 1, left, right)
# Remove character from left
char = s[left]
window_counts[char] -= 1
if char in needed and window_counts[char] < needed[char]:
have -= 1
left += 1
# Return the minimum window
length, left, right = result
return s[left:right + 1] if length != float('inf') else ""
Test case:
min_window_substring("ADOBECODEBANC", "ABC")â "BANC"
Key insight: The two-phase approachâexpand until valid, then contract to minimizeâis the hallmark of variable-size window problems. The nested while loop for contraction is what makes this pattern so powerful.
The Decision Framework: Fixed vs. Variable?
When you encounter a new problem, ask yourself:
Is the window size given or implied?
- YES â Fixed-size window
- NO â Check next question
Are you asked to find "longest" or "shortest" satisfying a condition?
- YES â Variable-size window
- NO â Check next question
Does the problem involve "at most K" or "exactly K" of something?
- YES â Variable-size window with counting
- NO â Might not be a sliding window problem
Does the problem ask about "every window of size K"?
- YES â Fixed-size window
- NO â Reevaluate if sliding window is the right approach
Common Pitfalls and How to Avoid Them
Mistake 1: Not Handling Empty Windows
Always check edge cases: empty arrays, k = 0, k > array length.
# Good practice
if not arr or k <= 0 or k > len(arr):
return appropriate_default_value
Mistake 2: Off-by-One Errors in Window Indices
Remember: window of size k starting at index i contains elements arr[i] through arr[i + k - 1].
# Window starts when we have k elements
if i >= k - 1: # Not i >= k!
# Process window
Mistake 3: Forgetting to Update State When Contracting
In variable-size windows, when you move the left pointer, you MUST update your window state.
# Wrong
left += 1
# Right
remove_element_from_state(arr[left])
left += 1
Mistake 4: Not Tracking the Window Range Correctly
For variable-size windows, the current window length is right - left + 1, not right - left.
# Current window: arr[left] to arr[right] inclusive
window_length = right - left + 1
Advanced Patterns and Variations
Once you've mastered the basics, you'll encounter problems that combine sliding window with other techniques:
Pattern A: Sliding Window + Two Pointers
Some problems require maintaining two conditions simultaneously. For example, finding a substring with exactly K distinct characters (not "at most K").
Approach: Find longest with at most K distinct, then subtract longest with at most (K-1) distinct.
Pattern B: Sliding Window + Hashing
When the window needs to track frequencies or sets of elements, combine with hash maps or sets.
Pattern C: Sliding Window + Monotonic Queue/Stack
For problems like "sliding window maximum" (LeetCode #239), you need a deque that maintains elements in monotonic order.
My Practice Strategy
Here's how I went from struggling with sliding window to solving them confidently:
Week 1: Master Fixed-Size Windows
- Solve 10-15 fixed-size window problems
- Focus on different types of state: sums, counts, frequencies
- Practice the template until it's muscle memory
Week 2: Tackle Variable-Size Windows
- Start with "longest substring" variations
- Move to "at most K" problems
- Finally attempt minimum window problems
Week 3: Mix and Match
- Solve problems without looking at the pattern type first
- Practice identifying the pattern from the problem statement
- Time yourselfâaim for recognition in 30 seconds, solution in 15 minutes
Real Interview Experience
I was once asked: "Given an array of integers and a number K, find the length of the longest subarray with sum equal to K."
My thought process (out loud):
- "This asks for 'longest' â likely variable-size window"
- "Condition is 'sum equal to K' â I'll track current sum"
- "I'll expand by adding elements, contract when sum exceeds K"
I coded the solution in about 10 minutes. The interviewer asked, "How did you know to use sliding window so quickly?" I explained the pattern recognition framework, and they were genuinely impressed by the systematic approach.
Beyond the Interview: Real-World Applications
Sliding window isn't just an interview trickâit's used in:
- Network protocols: TCP sliding window for flow control
- Image processing: Applying filters with sliding kernels
- Time series analysis: Moving averages and rolling statistics
- Streaming data: Processing real-time data with bounded memory
Understanding the technique deeply helps you recognize these patterns in real systems.
Conclusion: Your Sliding Window Mastery Roadmap
The sliding window technique is one of those rare algorithms that genuinely simplifies complex problems. Here's what you need to remember:
- Two patterns rule them all: Fixed-size and variable-size windows cover 95% of problems
- Pattern recognition is key: Learn to identify sliding window problems from the problem statement
- State management matters: Know what to track (sums, counts, frequencies, sets)
- Practice the templates: Muscle memory makes implementation trivial
Start with simple fixed-size problems. Once those feel easy, move to variable-size. Within 2-3 weeks of focused practice, you'll be solving hard-level sliding window problems confidently.
The best part? Once you internalize this pattern, you'll start seeing opportunities to apply it everywhereâin interviews, in real code, even in daily problem-solving.
Remember: every expert was once a beginner who kept practicing. The sliding window technique isn't magicâit's just a clever way to avoid redundant work. And now you know the secret.
Happy coding, and may your windows always slide smoothly!
If you found this guide helpful, share it with others preparing for technical interviews. The sliding window technique is one of those "aha!" moments that makes everything click into place. If this guide helped you master sliding window technique or solve subarray problems, I'd love to hear about it! Connect with me on Twitter or LinkedIn.
Support My Work
If this guide helped you master the sliding window technique, transformed how you approach array problems, or gave you confidence for your coding interviews, I'd really appreciate your support! Creating comprehensive, free content like this takes significant time and effort. Your support helps me continue sharing knowledge and creating more helpful resources for students like you.
â Buy me a coffee - Every contribution, big or small, means the world to me and keeps me motivated to create more content!
Cover image by Amel Majanovic on Unsplash