Sliding Window: Dynamic Subarray Problems

Solve maximum subarray, longest substring, and subarray average problems with O(n) time using the sliding window technique.

published: reading time: 16 min read author: GeekWorkBench

Sliding Window: Dynamic Subarray Problems

The sliding window pattern transforms nested iteration problems into single-pass solutions by maintaining a “window” of elements that expands and contracts as you traverse the data. Think of it as a conveyor belt: elements enter one end, process through the window, and exit the other. This gives you O(n) time for problems that would otherwise require O(n²) or O(n³) brute force approaches.

The power of sliding windows lies in their adaptability. Whether you need fixed-size windows for averaging problems or variable-size windows for longest-substring challenges, the same core pattern adapts to both. The key insight is that you don’t need to recalculate everything from scratch when the window moves—you can update your running calculation incrementally.

Introduction

The sliding window pattern maintains a contiguous “window” of elements as you traverse data, expanding and contracting based on problem constraints. Instead of recalculating from scratch when the window moves, you incrementally update a running calculation—subtract the element leaving, add the element entering. This transforms O(n²) or O(n³) subarray problems into O(n) single-pass solutions.

Many real-world problems involve finding optimal contiguous subsequences: maximum subarray sum of size k, longest substring without repeating characters, or minimum window containing all characters of a pattern. The O(1) space complexity makes this useful in memory-constrained environments, and the predictable pointer movement patterns reduce bugs compared to more complex recursive approaches.

This guide covers both fixed-size and variable-size sliding windows, with implementation details for longest substring with K distinct characters, minimum size subarray sum, and minimum window substring. Production scenarios cover boundary overflow, stale data from incorrect window updates, and hash map memory leaks.

When to Use

Sliding windows excel when problems involve:

  • Longest substring without repeating characters — Track character frequencies as window expands/contracts
  • Maximum sum subarray of size k — Maintain running sum, subtract element leaving window
  • Average of all subarray size k — Same as above divided by k
  • Permutation in string — Fixed-size window with frequency counting
  • Fruit into baskets — Variable-size window with at most two types

When Not to Use

  • Problems requiring all possible subarrays rather than optimal ones
  • Non-contiguous subarrays or subsequences (sliding windows require contiguous elements)
  • When hash map solutions offer clearer O(n) time with O(1) space average

Architecture: Fixed vs Variable Windows

graph TD
    A[Start with empty window] --> B[Expand: add elements from right]
    B --> C{Window valid?}
    C -->|Yes| D[Record answer]
    C -->|No| E[Contract: remove from left]
    D --> B
    E --> B
    B --> F[Continue until right reaches end]

Fixed window (size k): Add element entering, subtract element leaving, maintain running calculation.

Variable window (max/min longest): Expand freely, contract when constraint violated, record largest valid window.

Production Failure Scenarios

FailureCauseMitigation
Window size inconsistencyOff-by-one in window boundary calculationUse inclusive/exclusive boundaries consistently
Stale dataNot updating when window movesIncrementally update calculation, don’t recalculate full window
Memory leak in hash mapFrequency counts never decrementing to zeroClean up entries when frequency hits zero
Boundary overflowRight pointer exceeding array boundsAlways check right < n before processing

Trade-off Table

ApproachTimeSpaceBest For
Brute ForceO(n²k)O(1)Small n, fixed k
Prefix SumO(n)O(n)Range sum queries
Sliding WindowO(n)O(1) to O(k)Contiguous subarray problems
Divide & ConquerO(n log n)O(log n)When window constraint is complex

Implementation

Maximum Sum Subarray of Size K

def max_subarray_sum(arr, k):
    """
    Find maximum sum of any subarray with exactly k elements.
    """
    if len(arr) < k:
        return -1

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

    # Slide window: subtract element leaving, add element entering
    for i in range(k, len(arr)):
        window_sum += arr[i] - arr[i - k]
        max_sum = max(max_sum, window_sum)

    return max_sum

Longest Substring Without Repeating Characters

def length_of_longest_substring(s):
    """
    Find length of longest substring without repeating chars.
    Uses variable-size sliding window.
    """
    char_index = {}  # Most recent index of each character
    left = 0
    max_length = 0

    for right, char in enumerate(s):
        # Contract left if char already in window
        if char in char_index and char_index[char] >= left:
            left = char_index[char] + 1

        # Update character index and max length
        char_index[char] = right
        max_length = max(max_length, right - left + 1)

    return max_length

Minimum Size Subarray Sum

def min_subarray_len(target, nums):
    """
    Find minimum length subarray with sum >= target.
    Variable window: expand until valid, then contract for minimum.
    """
    left = 0
    current_sum = 0
    min_length = float('inf')

    for right in range(len(nums)):
        current_sum += nums[right]

        # Contract from left while still valid
        while current_sum >= target and left <= right:
            min_length = min(min_length, right - left + 1)
            current_sum -= nums[left]
            left += 1

    return min_length if min_length != float('inf') else 0

Common Pitfalls / Anti-Patterns

  1. Mixing up left/right movement — Right pointer always moves forward; left only moves when contracting
  2. Not handling empty input — Check for len(arr) == 0 or k == 0 upfront
  3. Integer overflow in running sum — Use appropriate data types for large sums
  4. Forgetting to update after contraction — The window might become valid again immediately after shrinking

Quick Recap Checklist

  • Fixed or variable window? Determines contraction logic
  • Handle empty input / k > n case
  • Right pointer enters: add to calculation
  • Left pointer exits: subtract from calculation
  • Test with all identical elements, single element, boundary k values

Interview Questions

1. What's the key advantage of sliding window over brute force?

Sliding window achieves O(n) vs O(n²) time complexity by reusing calculations from the previous window. When the window moves, only two elements change: the one leaving (subtract) and the one entering (add). Brute force recalculates the entire window each time, causing quadratic blowup.

2. How do you handle variable-size windows?

Variable-size windows expand freely and contract when constraints are violated. The pattern: always move right pointer forward to expand, then move left pointer forward to contract while the window is invalid. Track the best answer at each valid state.

3. Can you use sliding window on a linked list?

Yes, but with a limitation: sliding windows work on contiguous elements. For linked lists, you can simulate a window using two pointers separated by k nodes (fixed window) or maintain a queue-like structure (variable window) by traversing and storing references. However, array-based sliding windows are more performant due to O(1) index-based access.

4. How do you solve the Longest Repeating Character Replacement problem?

Use a variable-size sliding window with a frequency map. Track the max frequency of any character in the current window. The condition for a valid window is window_length - max_freq <= k (where k is allowed replacements). Expand right, update counts, and contract left when the condition fails. The answer is the longest valid window seen.

5. Explain the Minimum Window Substring problem and its solution.

Given strings S and T, find the smallest substring of S containing all characters of T (with duplicates). Use two hash maps (target counts and window counts) with a variable-size sliding window. Expand right until the window contains all characters, then contract left to minimize the window while still satisfying the condition. Track the minimum window start and length.

6. How would you find all anagrams of a pattern in a string?

Use a fixed-size sliding window equal to the pattern length. Build a frequency map of the pattern. Slide the window across the string, updating character frequencies incrementally — add the incoming character, remove the outgoing one. After each slide, compare the window's frequency map to the pattern's. If they match, record the starting index.

7. How does a deque help with Sliding Window Maximum?

Maintain a deque of indices where values are in decreasing order. For each new element: remove indices outside the window from the front, remove smaller values from the back, then add the new index. The front of the deque always holds the maximum for the current window. This gives O(n) time total because each element is added and removed at most once.

8. How do you find the longest subarray with at most K distinct elements?

Use a variable-size sliding window with a hash map tracking element frequencies. Expand the right pointer freely, adding elements to the map. When the map size exceeds K, contract from the left by decrementing counts and removing entries that hit zero. Track the maximum window length observed during any valid state.

9. What's the difference between fixed-size and variable-size sliding windows, and how does contraction logic differ between them?

Fixed-size windows keep a constant width of exactly k elements. The right pointer enters and the left pointer exits in lockstep — each slide subtracts the leftmost element and adds the new right one. Variable-size windows expand freely and only contract when a constraint breaks. The right pointer always moves forward, but the left pointer advances only as needed to restore validity. Contraction in variable windows lives inside a while loop; fixed windows use a straightforward for-loop step.

10. How do you handle the edge case where K is larger than the array length in a fixed-window problem?

Check upfront: if k > n, no valid subarray of size k exists, so return a sentinel value (-1, empty, or raise an exception depending on the problem). Variable windows handle this automatically — the window simply cannot reach size k, so the algorithm correctly returns 0 or handles the empty state.

11. How would you adapt a sliding window solution to handle negative numbers in the input?

Standard sliding window assumes monotonicity when searching for maximums or minimums, which breaks with negative numbers. For maximum subarray sum, you cannot discard the current sum just because it's negative — you keep it because the next negative element might make it even more negative. The fix: in problems like "Maximum Average Subarray," negative values still work with the prefix-sum approach. But for longest subarray satisfying a constraint, contraction must be based purely on the constraint itself (e.g., character frequency) not on the running sum sign.

12. Can a sliding window be applied to problems requiring a minimum window rather than a maximum one?

Yes — the Minimum Size Subarray Sum problem is a classic case. After expanding right and satisfying the constraint, you enter an inner contraction loop that greedily shrinks the window from the left as long as it stays valid. Each contraction potentially yields a new minimum. This flips the tracking metric compared to Maximum Window problems where you record the largest valid window. The direction of expansion and contraction stays the same; only what you're tracking changes.

13. How do you solve the "Count Subarrays with K Different Integers" problem using sliding window?

The trick is to compute countSubarraysWithAtMostKDistinct(k) - countSubarraysWithAtMostKDistinct(k-1). Write a helper that returns the count of subarrays with at most K distinct integers using a variable-size window. Slide the window: add the right element, update frequency counts. When the distinct count exceeds K, contract from the left until it's valid again. The total count at each step equals the window length (number of valid subarrays ending at right). This subtraction trick works for any "exactly K" variant of sliding window problems.

14. What is the Best Time to Buy and Sell Stock with Cooldown, and where does sliding window come in?

You can only sell after a cooldown of one day. This isn't a classic two-pointer problem but a DP problem where the "window" is actually a state machine with three states: holding a stock, not holding, or in cooldown. However, if you reframe finding maximum profit with a constraint on consecutive transactions, a deque-based sliding window can track the best recent buy opportunity. The more common solution uses O(1) space DP with the states: sell[i] = max(sell[i-1], hold[i-1] + price[i]) and hold[i] = max(hold[i-1], cooldown[i-1] - price[i]).

15. How would you solve the "Fruit Into Baskets" problem (at most two fruit types) with sliding window?

This is a direct application of the "longest subarray with at most K distinct elements" pattern where K=2. Use a hash map to track the count of each fruit type in the current window. Expand right by adding fruits; when a third type would enter, contract from the left by removing fruits until only two types remain. Track the maximum window size. The time complexity is O(n) because each fruit is added and removed at most once.

16. What happens if you use inclusive vs exclusive boundaries incorrectly in a sliding window implementation?

Off-by-one errors are the most common sliding window bug. With [left, right] inclusive on both ends, the window length is right - left + 1. With [left, right) exclusive on right, length is right - left. Mixing these conventions within the same function — for example, using inclusive when checking validity but exclusive when calculating length — produces wrong answers. Pick one convention and apply it consistently across all boundary comparisons, initial window setup, and contraction loop conditions.

17. How do you handle duplicate characters in the Longest Substring Without Repeating Characters problem?

When a duplicate character enters the window, you must contract from the left until that character is no longer present. The standard approach stores the most recent index of each character. When character c at index right is seen again, if char_index[c] >= left, you update left = char_index[c] + 1. This jump is safe because all elements before the previous occurrence are now irrelevant — the window must start after the last seen index of c to remain valid.

18. Can you use a monotonic queue with sliding windows, and if so, what advantage does it provide?

Yes. A monotonic deque keeps elements in sorted order within the window, enabling O(1) retrieval of min or max. In the Sliding Window Maximum problem, the deque stores indices in decreasing order of their values — the front is always the maximum. As the window slides, you remove indices outside the window from the front and remove indices of values smaller than the incoming element from the back. Each element is processed at most twice (once entering, once leaving), giving O(n) total time.

19. How do you find the maximum sum subarray of size K when K is not known at compile time?

This is really about the "Maximum Average Subarray" pattern. If K is fixed per test case, the sliding window code works as-is. If K must be found (e.g., find the subarray length that gives maximum average with sum >= threshold), you combine sliding window with binary search on K, or you use a variable-size window that tracks the sum-to-length ratio. Sliding window itself does not require K to be known at compile time — you pass it as a parameter at runtime.

20. What is the difference between sliding window and the two-pointer technique, and when would you choose one over the other?

Two-pointer uses two pointers moving independently toward each other (common in sorted array pair problems). Sliding window is a specialized two-pointer variant where both pointers move in the same direction with an overlapping active region — the window. Use sliding window when you need to track a property of the current contiguous segment (max sum, longest substring, valid anagram). Use two-pointer when the pointers define a search range that shrinks from both ends (binary-search-like, pair finding, partition). Sliding window always gives O(n) total pointer movement; general two-pointer can be O(n) or O(n²) depending on implementation.

Further Reading

To deepen your understanding of the sliding window technique, explore these resources:

Books

  • Cracking the Coding Interview by Gayle Laakmann McDowell — Covers sliding window problems in the arrays and strings chapters
  • Grokking Algorithms by Aditya Bhargava — Visual explanations of the sliding window pattern
  • Elements of Programming Interviews — Advanced problems with sliding window variants

LeetCode Practice Problems

ProblemDifficultyKey Concept
Longest Substring Without Repeating CharactersMediumVariable-size window
Minimum Window SubstringHardTwo hash maps + variable window
Sliding Window MaximumHardDeque optimization
Fruit Into BasketsMediumAt-most-K distinct constraint
Permutation in StringMediumFixed-size frequency window
Longest Repeating Character ReplacementMediumCharacter count + max frequency

Advanced Topics

  • Two-pointer technique: The broader category that sliding window belongs to
  • Deque-based sliding windows: Used when you need min/max in O(1) per window (e.g., Sliding Window Maximum)
  • Sliding window with monotonic queue: Combines deque with monotonic ordering for optimal performance

Conclusion

Sliding windows turn O(n²) or O(n³) brute force into single-pass O(n) by updating a running calculation as the window moves. Fixed windows are straightforward—add incoming, subtract outgoing. Variable windows expand freely and contract when a constraint breaks. The catch: windows only work on contiguous data. For problems where that’s not an option, hash maps tend to be the alternative.

Category

Related Posts

Two Pointers Technique: Efficient Array Traversal

Master the two pointers technique for O(1) space complexity solutions to array problems like pair sum, palindrome check, and triplet finding.

#two-pointers #algorithms #data-structures

Arrays vs Linked Lists: Understanding the Trade-offs

Compare arrays and linked lists in terms of access time, insertion/deletion efficiency, memory usage, and cache performance.

#arrays #linked-lists #data-structures

Arrays: 1D, 2D, and Multi-dimensional Mastery

Master array operations, traversal, search, common patterns like two-pointer and sliding window, and when to use multi-dimensional arrays.

#arrays #1d-arrays #2d-arrays