Sliding Window Technique

Type: Software Reference Confidence: 0.95 Sources: 7 Verified: 2026-02-24 Freshness: 2026-02-24

TL;DR

Constraints

Quick Reference

PatternWindow TypeTimeSpaceClassic Problems
Fixed-size sum/avgFixedO(n)O(1)Max sum subarray of size k, moving average
Fixed-size with hashFixedO(n)O(k)Permutation in string, anagram check
Variable shrink (find minimum)VariableO(n)O(k)Minimum window substring, smallest subarray with sum ≥ target
Variable expand (find maximum)VariableO(n)O(k)Longest substring without repeating chars, longest with at most k distinct
Sliding window maximum/minimumFixedO(n)O(k)Sliding window maximum (deque-based)
Count-basedVariableO(n)O(k)Subarrays with k different integers, count of nice subarrays
Flip/toggleVariableO(n)O(1)Max consecutive ones III (flip at most k zeros)
Two-frequencyVariableO(n)O(1)Longest repeating character replacement

Decision Tree

START
├── Is the problem about a contiguous subarray or substring?
│   ├── NO → Not a sliding window problem. Consider two pointers, DP, or binary search.
│   └── YES ↓
├── Is the window size given (fixed k)?
│   ├── YES → Use FIXED-SIZE window template
│   │   ├── Need max/min of window elements? → Use monotonic deque (O(n))
│   │   └── Need sum/count/frequency? → Use running sum + hash map
│   └── NO → Variable-size window ↓
├── Are you looking for the SMALLEST valid window?
│   ├── YES → Use VARIABLE SHRINK template
│   │   └── Expand right until valid, then shrink left to find minimum
│   └── NO ↓
├── Are you looking for the LONGEST valid window?
│   ├── YES → Use VARIABLE EXPAND template
│   │   └── Expand right, shrink left only when invalid, track max length
│   └── NO ↓
└── Counting valid subarrays?
    └── YES → Use "at most K" trick: count(exactly K) = count(at most K) - count(at most K-1)

Step-by-Step Guide

1. Identify the window type

Determine whether the problem specifies a fixed window size k or requires you to find an optimal (minimum/maximum) window. If the problem says "subarray of size k" or "every k consecutive elements," use the fixed template. If it says "smallest subarray such that..." or "longest substring where...," use the variable template. [src1]

2. Initialize the window state

Set up tracking variables: left = 0, running sum/counter/hash map, and result variable. For hash map problems, use collections.Counter (Python), Map (JavaScript), or HashMap (Java). [src3]

left = 0
window_state = {}  # or: current_sum = 0
result = float('inf')  # for minimum; use float('-inf') or 0 for maximum

3. Expand the window (move right pointer)

Iterate right from 0 to len(arr)-1. On each step, add arr[right] to the window state. For sum problems: current_sum += arr[right]. For frequency problems: window_state[arr[right]] += 1. [src2]

4. Shrink the window (move left pointer)

For fixed windows: shrink when right - left + 1 > k. For variable windows: shrink while the window is invalid (shrink template) or while the window violates the constraint (expand template). On each shrink, remove arr[left] from state and increment left. [src3]

5. Update the result

After adjusting the window, check if the current window is a candidate for the answer. For minimum problems, update when the window becomes valid. For maximum problems, update on every step. [src4]

Verify: Run through a small example manually — the left pointer should never exceed right, and both should reach the end exactly once, confirming O(n).

Code Examples

Python: Maximum Sum Subarray of Size k (Fixed Window)

# Input:  arr = [2, 1, 5, 1, 3, 2], k = 3
# Output: 9 (subarray [5, 1, 3])

def max_sum_subarray(arr, k):
    n = len(arr)
    if n < k:
        return -1

    window_sum = sum(arr[:k])  # first window
    max_sum = window_sum

    for right in range(k, n):
        window_sum += arr[right] - arr[right - k]  # slide: add new, remove old
        max_sum = max(max_sum, window_sum)

    return max_sum

Python: Minimum Window Substring (Variable Shrink)

# Input:  s = "ADOBECODEBANC", t = "ABC"
# Output: "BANC"

from collections import Counter

def min_window(s, t):
    need = Counter(t)
    missing = len(t)  # chars still needed
    left = 0
    best = (0, float('inf'))  # (start, end)

    for right, char in enumerate(s):
        if need[char] > 0:
            missing -= 1
        need[char] -= 1

        while missing == 0:  # window is valid — try to shrink
            if right - left < best[1] - best[0]:
                best = (left, right)
            need[s[left]] += 1
            if need[s[left]] > 0:
                missing += 1
            left += 1

    return "" if best[1] == float('inf') else s[best[0]:best[1] + 1]

JavaScript: Longest Substring Without Repeating Characters (Variable Expand)

// Input:  s = "abcabcbb"
// Output: 3 (substring "abc")

function lengthOfLongestSubstring(s) {
  const seen = new Map(); // char -> last index
  let left = 0;
  let maxLen = 0;

  for (let right = 0; right < s.length; right++) {
    if (seen.has(s[right]) && seen.get(s[right]) >= left) {
      left = seen.get(s[right]) + 1; // shrink past duplicate
    }
    seen.set(s[right], right);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

Java: Max Consecutive Ones III (Variable Expand with Flip Budget)

// Input:  nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
// Output: 6 (flip two 0s to get [1,1,1,0,0,1,1,1,1,1,1])

public int longestOnes(int[] nums, int k) {
    int left = 0, zeros = 0, maxLen = 0;

    for (int right = 0; right < nums.length; right++) {
        if (nums[right] == 0) zeros++;

        while (zeros > k) {        // too many flips — shrink
            if (nums[left] == 0) zeros--;
            left++;
        }
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

Anti-Patterns

Wrong: Using nested loops for contiguous subarray problems

# BAD — O(n^2) brute force for max sum subarray of size k
def max_sum_brute(arr, k):
    max_sum = 0
    for i in range(len(arr) - k + 1):
        current = sum(arr[i:i+k])  # recalculates entire window each time
        max_sum = max(max_sum, current)
    return max_sum

Correct: Slide the window incrementally

# GOOD — O(n) sliding window
def max_sum_slide(arr, k):
    window_sum = sum(arr[:k])
    max_sum = window_sum
    for i in range(k, len(arr)):
        window_sum += arr[i] - arr[i - k]  # O(1) update
        max_sum = max(max_sum, window_sum)
    return max_sum

Wrong: Not updating state when shrinking the window

# BAD — shrinks left pointer but forgets to remove element from hash map
def longest_unique_bad(s):
    seen = set()
    left = 0
    max_len = 0
    for right in range(len(s)):
        seen.add(s[right])
        while s[right] in seen and len(seen) > right - left + 1:
            left += 1  # moves left but never removes s[left] from seen!
        max_len = max(max_len, right - left + 1)
    return max_len

Correct: Remove outgoing element from state on every shrink

# GOOD — properly maintains the set
def longest_unique_good(s):
    seen = set()
    left = 0
    max_len = 0
    for right in range(len(s)):
        while s[right] in seen:
            seen.remove(s[left])  # remove before moving left
            left += 1
        seen.add(s[right])
        max_len = max(max_len, right - left + 1)
    return max_len

Wrong: Resetting left pointer to 0 on each mismatch

# BAD — resets left to 0, destroying O(n) guarantee
def min_subarray_bad(arr, target):
    for right in range(len(arr)):
        left = 0  # WRONG: restarts from beginning every time
        while left <= right and sum(arr[left:right+1]) >= target:
            left += 1
    # This is O(n^2) despite looking like sliding window

Correct: Left pointer only moves forward

# GOOD — left only advances, never resets
def min_subarray_good(arr, target):
    left = 0
    current_sum = 0
    min_len = float('inf')
    for right in range(len(arr)):
        current_sum += arr[right]
        while current_sum >= target:
            min_len = min(min_len, right - left + 1)
            current_sum -= arr[left]
            left += 1  # only moves forward
    return min_len if min_len != float('inf') else 0

Common Pitfalls

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Finding max/min/count of contiguous subarray or substringElements are not contiguous (subsequence problems)Dynamic programming
Problem says "subarray of size k" or "window of length k"Need to find pairs in sorted array (two-sum variant)Two-pointer (converging)
Optimizing longest/shortest subarray meeting a conditionArray has negative numbers and need exact subarray sumPrefix sum + hash map
Condition is monotonic (expanding only worsens/improves)Comparing non-adjacent elementsBinary search or divide & conquer
String pattern matching within a window (anagrams, permutations)Longest increasing subsequence (non-contiguous)Patience sorting / DP
Counting subarrays satisfying a propertyData structure is a tree or graphBFS/DFS traversal

Important Caveats

Related Units