Sliding Window

Medium
Time: O(n)Space: O(k) where k = window size or charset size
0/12
problems solved
0%
1.

Pattern Overview: The Sliding Window Technique

The Sliding Window pattern is one of the most powerful techniques for solving contiguous subarray and substring problems. Instead of recalculating everything from scratch for each position, you maintain a "window" that slides through the data, efficiently updating state by adding elements on one side and removing them from the other.

Two Types of Sliding Window:

  1. Fixed Size Window: Window size k stays constant. Add right element, process window, remove left element.

  2. Variable Size Window: Window expands and contracts based on constraints. Expand right freely, shrink left when constraint violated.

The Key Insight: Both types run in O(n) because each element is added at most once and removed at most once.

When to Use Sliding Window:

  • Problems mentioning "contiguous subarray" or "substring"
  • Finding longest/shortest subarray with a constraint
  • Maximum/minimum sum of k consecutive elements
  • Anagram or permutation finding
  • Character replacement within a limit
2.

Fixed Size Window: Maximum Sum

Fixed-size sliding window is the simplest form. The window always contains exactly k elements. As the window slides, you add the new right element and remove the old left element.

Template Pattern:

  1. Add element at right pointer to window state
  2. If window has k elements: record result, then remove leftmost element
  3. Move both pointers together

Example: Maximum Sum of K Consecutive Elements Array: [2, 1, 5, 1, 3, 2], k = 3

Window positions:

  • [2, 1, 5] = 8 (sum)
  • [1, 5, 1] = 7
  • [5, 1, 3] = 9 <- Maximum!
  • [1, 3, 2] = 6

Instead of summing k elements each time (O(n*k)), we update incrementally:

  • Add right element: sum += arr[i]
  • Remove left element: sum -= arr[i - k + 1]

This gives us O(n) time complexity.

Code
Java

Interactive Fixed Window

Fixed Size Sliding Window

Find maximum sum of k consecutive elements

Speed:
Window size k = 3
Array:
2[0]
1[1]
5[2]
1[3]
3[4]
2[5]
Current Window Sum
0
Maximum Sum
-
Best Window
-
Build Window
Slide Window
Click Play to find maximum sum of k=3 consecutive elements

Key Insight: Instead of summing k elements each time O(k), update incrementally: newSum = oldSum + arr[right] - arr[left]. O(1) per slide!

3.

Interactive: Fixed Window Visualizer

Watch how the fixed-size window slides through the array, maintaining the sum by adding one element and removing another each step.

Interactive Fixed Window

Fixed Size Sliding Window

Find maximum sum of k consecutive elements

Speed:
Window size k = 3
Array:
2[0]
1[1]
5[2]
1[3]
3[4]
2[5]
Current Window Sum
0
Maximum Sum
-
Best Window
-
Build Window
Slide Window
Click Play to find maximum sum of k=3 consecutive elements

Key Insight: Instead of summing k elements each time O(k), update incrementally: newSum = oldSum + arr[right] - arr[left]. O(1) per slide!

4.

Variable Size: Finding Maximum Length

Variable-size windows expand and contract based on a constraint. For "longest/maximum" problems, you expand freely and shrink only when the constraint is violated.

Template Pattern:

  1. EXPAND: Add s[right] to window state
  2. SHRINK: While window is invalid, remove s[left] and increment left
  3. UPDATE: Record result AFTER shrinking (window is now valid)

Example: Longest Substring Without Repeating Characters String: "abcabcbb"

  • "a" - valid, length 1
  • "ab" - valid, length 2
  • "abc" - valid, length 3 <- track max
  • "abca" - 'a' repeats! Shrink until valid
  • "bca" - valid, length 3
  • "bcab" - 'b' repeats! Shrink...
  • "cab" - valid, length 3
  • And so on...

Key Insight: Use a Set (or HashMap) to track characters in the current window. When you see a duplicate, shrink from the left until it's removed.

Code
Java
5.

Interactive: Longest Substring Visualizer

See how the variable-size window expands to include new characters and contracts when duplicates are found.

Interactive Longest Substring

Longest Substring Without Repeating

Variable-size window with Set for uniqueness

Speed:
String: "abcabcbb"
a0
b1
c2
a3
b4
c5
b6
b7
Characters in Window (Set):
Empty
Current Window
""
Current Length
0
Max Length
0
Expanding →
← Shrinking
Click Play to find longest substring without repeating characters

Key Insight: Use a Set to track characters in window. When duplicate found, shrink from left until the duplicate is removed. Update max AFTER shrinking (when window is valid).

6.

Variable Size: Finding Minimum Length

For "shortest/minimum" problems, the logic flips. You want the smallest valid window, so you record the result INSIDE the while loop (when the window is valid) and keep shrinking to find smaller valid windows.

Template Pattern:

  1. EXPAND: Add element to window
  2. While window is VALID:
    • UPDATE: Record result (inside the loop!)
    • SHRINK: Remove left element and try to find smaller window

Example: Minimum Size Subarray Sum Find shortest subarray with sum >= target Array: [2, 3, 1, 2, 4, 3], target = 7

  • [2, 3, 1, 2] sum=8 >= 7, record length 4, try shrinking
  • [3, 1, 2] sum=6 < 7, not valid, expand
  • [3, 1, 2, 4] sum=10 >= 7, record length 4, shrink
  • [1, 2, 4] sum=7 >= 7, record length 3, shrink
  • [2, 4] sum=6 < 7, expand
  • [2, 4, 3] sum=9 >= 7, record length 3, shrink
  • [4, 3] sum=7 >= 7, record length 2 <- minimum!

Answer: 2

Code
Java
7.

Anagram Finding with Frequency Counter

Finding anagrams requires tracking character frequencies. The key optimization is using a "matches" counter instead of comparing entire frequency maps each step.

The Matches Counter Technique:

  1. Build frequency map of pattern
  2. Track how many unique characters have matching frequencies
  3. When matches equals required unique chars, we found an anagram

Example: Find All Anagrams String: "cbaebabacd", Pattern: "abc"

Pattern frequency: {a:1, b:1, c:1}, required = 3 unique chars

Slide fixed window of size 3:

  • "cba": {c:1, b:1, a:1} - matches=3, found at index 0!
  • "bae": {b:1, a:1, e:1} - matches=2
  • "aeb": same
  • "eba": same
  • "bab": {b:2, a:1} - matches=1
  • "aba": {a:2, b:1} - matches=1
  • "bac": {b:1, a:1, c:1} - matches=3, found at index 6!
  • "acd": {a:1, c:1, d:1} - matches=2

Result: [0, 6]

Code
Java

Interactive Find Anagrams

Find All Anagrams

Fixed window with frequency matching counter

Speed:
Pattern: "abc"
Required: {a:1, b:1, c:1} (3 chars)
String: "cbaebabacd"
c0
b1
a2
e3
b4
a5
b6
a7
c8
d9
Pattern Frequency:
a: 1
b: 1
c: 1
Window Frequency:
Empty
Matches
0/3
Window
-
Found
0
Click Play to find all anagrams of "abc" in the string

Key Insight: Track how many unique characters have matching frequencies. When matches equals required unique chars, the window is an anagram. O(n) with a "matches" counter!

8.

Interactive: Find Anagrams Visualizer

Watch the frequency matching process as the window slides through the string, tracking when all character frequencies match the pattern.

Interactive Find Anagrams

Find All Anagrams

Fixed window with frequency matching counter

Speed:
Pattern: "abc"
Required: {a:1, b:1, c:1} (3 chars)
String: "cbaebabacd"
c0
b1
a2
e3
b4
a5
b6
a7
c8
d9
Pattern Frequency:
a: 1
b: 1
c: 1
Window Frequency:
Empty
Matches
0/3
Window
-
Found
0
Click Play to find all anagrams of "abc" in the string

Key Insight: Track how many unique characters have matching frequencies. When matches equals required unique chars, the window is an anagram. O(n) with a "matches" counter!

9.

Longest Repeating Character Replacement

This problem combines variable-size window with a frequency counter. The key insight is that we can replace at most k characters, so the window is valid if:

windowSize - maxFrequency <= k

This means: characters we need to replace <= allowed replacements

Example: "AABABBA", k = 1

  • "A" - maxFreq=1, size=1, replace=0 <= 1, valid, len=1
  • "AA" - maxFreq=2, size=2, replace=0 <= 1, valid, len=2
  • "AAB" - maxFreq=2, size=3, replace=1 <= 1, valid, len=3
  • "AABA" - maxFreq=3, size=4, replace=1 <= 1, valid, len=4 <- max!
  • "AABAB" - maxFreq=3, size=5, replace=2 > 1, shrink!
  • "ABAB" - maxFreq=2, size=4, replace=2 > 1, shrink!
  • "BAB" - maxFreq=2, size=3, replace=1 <= 1, valid
  • And so on...

Optimization: We don't need to decrease maxFreq when shrinking. A larger maxFreq can only help us find longer valid windows, so we only update it when we find a higher frequency.

Code
Java
10.

Minimum Window Substring

This is the hardest sliding window problem. Find the minimum window in s that contains all characters of t (including duplicates).

Strategy: Variable size, find minimum, use matches counter.

Example: s = "ADOBECODEBANC", t = "ABC"

We need: {A:1, B:1, C:1}, required = 3 unique chars

Expand until valid, then shrink while staying valid:

  • "ADOBEC" - has A, B, C - valid! length=6, try shrinking
  • "DOBEC" - missing A - invalid, expand
  • "DOBECODEBA" - valid again, length=10
  • Keep shrinking: "CODEBA" (6), "ODEBA" invalid...
  • Eventually find "BANC" - length=4, this is minimum!

Key Difference from Find Anagrams:

  • Window size is variable (not fixed at pattern length)
  • We shrink WHILE valid to find minimum
  • Track the actual substring, not just starting indices
Code
Java
11.

Max Consecutive Ones III

Problem: Given binary array and k, return max consecutive 1s if you can flip at most k 0s.

Reframe: Find longest subarray with at most k zeros.

Example: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2

Window expands, tracking zero count:
[1,1,1] - zeros=0, len=3
[1,1,1,0] - zeros=1, len=4
[1,1,1,0,0] - zeros=2, len=5
[1,1,1,0,0,0] - zeros=3 > k, shrink!
[1,1,0,0,0] - zeros=3, shrink!
[1,0,0,0] - zeros=3, shrink!
[0,0,0] - zeros=3, shrink!
[0,0] - zeros=2, len=2
[0,0,1] - zeros=2, len=3
...
[0,0,1,1,1,1] - zeros=2, len=6 <- max!

Key Insight: We're not actually flipping anything. We're just finding the longest window with at most k zeros.

Code
Java
12.

Fruit Into Baskets (At Most K Distinct)

Problem: Collect maximum fruits using 2 baskets. Each basket holds one type. Must pick consecutive trees.

Translation: Find longest subarray with at most 2 distinct elements.

This generalizes to at most K distinct elements.

Example: fruits = [1,2,1,2,3], k=2

[1] - types={1}, len=1
[1,2] - types={1,2}, len=2
[1,2,1] - types={1,2}, len=3
[1,2,1,2] - types={1,2}, len=4 <- max!
[1,2,1,2,3] - types={1,2,3}=3 > 2, shrink!
[2,1,2,3] - types={1,2,3}=3, shrink!
[1,2,3] - types={1,2,3}=3, shrink!
[2,3] - types={2,3}=2, len=2

Key Insight: Track frequency map size. When size > k, shrink until we remove a fruit type entirely (frequency becomes 0).

Code
Java
13.

Subarrays with Exactly K Distinct

Problem: Count subarrays with exactly K distinct integers.

Challenge: "Exactly K" is hard to track directly with sliding window.

Brilliant Trick: exactlyK = atMostK(K) - atMostK(K-1)

Why This Works:

  • atMostK(K) counts all subarrays with 1, 2, ..., K distinct elements
  • atMostK(K-1) counts all subarrays with 1, 2, ..., K-1 distinct elements
  • Subtracting gives exactly those with K distinct

Example: nums = [1,2,1,2,3], K=2

atMostK(2) counts: [1], [1,2], [2], [2,1], [1,2,1], [1], [1,2], [2], [2,3], [3], ... atMostK(1) counts: [1], [2], [1], [2], [3], ... exactly(2) = difference

Implementation: Run atMostK twice, subtract results.

Code
Java
14.

Sliding Window Maximum (Monotonic Deque)

Problem: Given array and window size k, return max element in each window position.

Naive: O(n*k) - check all k elements each position. Optimal: O(n) - use monotonic deque!

Monotonic Deque Strategy:

  • Maintain deque of indices in DECREASING order of values
  • Front of deque is always the maximum
  • When adding new element, remove smaller elements from back
  • When sliding, remove front if it's outside window

Example: nums = [1,3,-1,-3,5,3,6,7], k = 3

i=0: deque=[0] (1)
i=1: deque=[1] (3 > 1, remove 0)
i=2: deque=[1,2] (−1 < 3, keep both) max=3
i=3: deque=[1,3] (−3 < 3) max=3
i=4: deque=[4] (5 > all, clear) max=5
i=5: deque=[4,5] (3 < 5) max=5
i=6: deque=[6] (6 > all) max=6
i=7: deque=[7] (7 > all) max=7
Output: [3,3,5,5,6,7]
Code
Java
15.

Permutation in String

Problem: Check if s2 contains a permutation of s1.

Translation: Does any substring of s2 have the same character frequencies as s1?

Approach: Fixed-size window (size = s1.length), track matching frequencies.

Optimization: Instead of comparing entire maps, use matches counter.

Example: s1 = "ab", s2 = "eidbaooo"

Target: {a:1, b:1}

"ei" - {e:1, i:1} - matches=0
"id" - {i:1, d:1} - matches=0
"db" - {d:1, b:1} - matches=1 (b matches!)
"ba" - {b:1, a:1} - matches=2 = required! TRUE

Key Insight: This is the same as "Find All Anagrams" but returns boolean on first match.

Code
Java
16.

Common Edge Cases

Edge Cases to Handle:

1. Empty Input

if (s.length === 0) return 0;
if (k > arr.length) return -1; // Invalid k

2. Window Larger Than Array

if (k > nums.length) return nums.length; // All elements

3. No Valid Window Exists

return minLen === Infinity ? 0 : minLen;
return result === '' ? '' : result;

4. Single Element

// Single element satisfies most constraints
[5], k=1 → max sum = 5
"a", find 'a' → found at index 0

5. All Same Elements

"aaaa", k=2 → longest repeating = 4 (no replacements needed)
[1,1,1,1] → max consecutive ones = 4

Common Mistakes:

MistakeFix
Off-by-one in window sizeUse right - left + 1
Updating result at wrong placeMax: after shrink, Min: inside shrink
Not handling empty resultCheck result === Infinity
Forgetting to remove from mapif (freq === 0) map.delete(key)
Using while instead of ifVariable window needs while
17.

Pattern Recognition Guide

Fixed vs Variable Window Decision Tree:

Is the window size given (k)?
├── YES: Fixed Size Window
│ └── Slide by adding right, removing left
└── NO: Variable Size Window
├── Finding MAXIMUM/LONGEST?
│ └── Update AFTER shrinking (when valid)
│ └── Examples: Longest substring, max consecutive
└── Finding MINIMUM/SHORTEST?
└── Update INSIDE shrinking loop (while valid)
└── Examples: Min window substring, min subarray sum

Problem Pattern Quick Reference:

Signal WordsPatternKey Technique
"k consecutive elements"Fixed windowAdd/remove at boundaries
"longest without X"Variable, maxSet for tracking
"at most k distinct"Variable, maxMap.size
"exactly k distinct"atMost(k) - atMost(k-1)Two-pass trick
"minimum subarray sum >= k"Variable, minUpdate inside while
"contains permutation/anagram"Fixed (pattern.length)Frequency match
"sliding window maximum"Fixed with dequeMonotonic deque

Data Structure Selection:

NeedUse
No duplicates allowedSet
Count occurrencesMap/Array
Track distinct countMap.size
Find max in windowMonotonic Deque
Anagram matchingFrequency array + matches counter
18.

Complexity Analysis

Time Complexity: O(n)

Despite nested loops (for + while), sliding window is O(n) because:

  • Each element is added to window at most once (right pointer)
  • Each element is removed from window at most once (left pointer)
  • Total operations = 2n = O(n)

Space Complexity:

  • Fixed window (no map): O(1)
  • With HashMap: O(k) where k is the size of the character set
    • For lowercase letters: O(26) = O(1)
    • For all ASCII: O(128) = O(1)
    • For Unicode: O(k) where k is unique characters
  • Monotonic deque: O(k) where k is window size

Problem-Specific Complexity:

ProblemTimeSpace
Max sum k elementsO(n)O(1)
Longest without repeatingO(n)O(min(n, charset))
Min window substringO(n + m)O(charset)
Find all anagramsO(n)O(1)
Sliding window maximumO(n)O(k)
Exactly K distinctO(n)O(k)

Why Sliding Window Works: The key insight is that we never "go back." Both left and right pointers only move forward. This monotonic property guarantees linear time.

Common Optimizations:

  1. Use array instead of HashMap for fixed alphabets
  2. Track maxFrequency without recalculating
  3. Jump left pointer directly using lastSeen map
19.

Template Summary

Fixed Size Window Template:

function fixedWindow(arr, k):
windowState = initial
result = initial
for i in 0 to arr.length:
add arr[i] to windowState
if i >= k - 1: // Window is full
update result
remove arr[i - k + 1] from windowState
return result

Variable Size - Maximum:

function variableMax(arr):
left = 0, result = 0
windowState = initial
for right in 0 to arr.length:
add arr[right] to windowState
while windowIsInvalid():
remove arr[left] from windowState
left++
result = max(result, right - left + 1) // AFTER while
return result

Variable Size - Minimum:

function variableMin(arr):
left = 0, result = Infinity
windowState = initial
for right in 0 to arr.length:
add arr[right] to windowState
while windowIsValid(): // Note: VALID, not invalid
result = min(result, right - left + 1) // INSIDE while
remove arr[left] from windowState
left++
return result

Exactly K Trick:

exactlyK(k) = atMostK(k) - atMostK(k-1)

Interview Tips:

  • Draw the window as you walk through examples
  • Always clarify: max or min? fixed or variable?
  • For frequency problems, consider matches counter
  • Remember: update location differs for max vs min

Test Your Knowledge

Take a quick 15question quiz to test what you've learned.