Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 4

Dynamic Sliding Windows for Subarray/Substring Problems

Recommended resources

Hello and welcome to our next lesson!

In our previous session, we mastered the Dutch National Flag algorithm, a powerful three-pointer technique for partitioning an array. This gave us a taste of how multiple pointers can work together to solve problems efficiently in a single pass.

Today, we'll build on that foundation by exploring one of the most important patterns for array and string problems: the Sliding Window. Specifically, we will focus on the variable-size sliding window, a technique designed to find the longest or shortest contiguous subarray/substring that satisfies a certain condition. This pattern is a cornerstone of FAANG interview questions, and mastering it will significantly boost your ability to solve a wide range of medium-level problems.

By the end of this lesson, you will be able to identify problems solvable with a variable-size sliding window and implement an efficient, single-pass solution.

1. The Sliding Window: A Dynamic Viewpoint

Imagine you have a pair of pointers, left and right, that define a "window" over a sequence (like an array or string). Unlike the fixed-size window problems you might have seen, here the window's size will dynamically grow and shrink.

  • Expansion: The window grows by moving the right pointer to the right, including a new element.
  • Contraction: The window shrinks by moving the left pointer to the right, excluding an element.

The core idea is to expand the window until it violates a given condition, and then contract it until it becomes valid again, all while keeping track of the best solution found so far.

This animation perfectly illustrates a variable-size window in action, finding the longest substring with unique characters.

Variable-Size Sliding Window for Longest Substring
This GIF shows a window expanding to include 'a', 'b', 'c'. When it tries to add a duplicate 'a', the window must shrink from the left to remove the original 'a' before it can continue expanding.

This approach is highly efficient because it avoids re-calculating information for every possible subarray. Instead of a brute-force O(n²) solution, we process each element at most twice (once by the right pointer and once by the left), leading to an optimal O(n) time complexity.


2. The General Template for Variable-Size Windows

For a developer like yourself, thinking in terms of reusable templates is key. The variable-size sliding window pattern has a very consistent structure.

Master the Sliding Window Technique

Let's examine a guide from Medium that breaks down the sliding window technique. It provides a clear, generic JavaScript template that we can adapt to solve many different problems. This is the blueprint for the pattern.

Please read the sections titled 'Variable Window Size Technique' and the 'Generic JavaScript Template' that follows it. Then, jump to 'Advanced Sliding Window Patterns' and look at 'Pattern 2: Growing Window (Find Maximum)'. This template is what we'll use for 'longest/maximum' problems.

The template for finding a maximum length subarray/substring looks like this:

function findMaximumWindow(arr, condition) {
    let left = 0;
    let maxLength = 0;
    let windowState = {}; // Can be a hash map, a sum, etc.

    // 1. Expand the window with the 'right' pointer
    for (let right = 0; right < arr.length; right++) {
        // Update the state with the new element
        updateWindowState(windowState, arr[right], 'add');

        // 2. Shrink the window while the condition is violated
        while (/* condition is violated */) {
            // Update the state by removing the 'left' element
            updateWindowState(windowState, arr[left], 'remove');
            left++;
        }

        // 3. At this point, the window is valid.
        // Update the result.
        maxLength = Math.max(maxLength, right - left + 1);
    }

    return maxLength;
}

This simple structure is incredibly powerful. Let's see it in action.


3. Application 1: Finding the Longest Substring

A classic application is finding the "Longest Substring with At Most K Distinct Characters". This pattern also covers variations like "Longest Substring Without Repeating Characters" (where K=1) and "Fruits into Baskets" (where K=2).

To understand the mechanics, let's watch a video that walks through these specific problems.

Coding Interview Patterns - Sliding Window | 10 different problems in a single video

This video by Nikhil Lohia provides an excellent visual explanation of how the variable-size window solves these problems. Pay close attention to how a hash map (or frequency map) is used to maintain the 'windowState'.

Watch from 07:58 to 16:56. This covers three problems back-to-back that all use the same underlying pattern: 'Longest Substring Without Repeating Characters', 'Longest Substring with At Most K Distinct Characters', and 'Fruits into Baskets'.

Let's recap the logic for "Longest Substring with At Most K Distinct Characters":

  • windowState: A hash map (charFrequency) to store the counts of characters currently in the window.
  • Condition Violation: The number of unique keys in our map is greater than K (Object.keys(charFrequency).length > K).
  • Expansion (right pointer moves): Add the character str[right] to the map and/or increment its count.
  • Contraction (left pointer moves):
    • Get the character str[left].
    • Decrement its count in the map.
    • If its count becomes 0, remove the character from the map.
    • Increment left.
  • Update Result: After each valid expansion, maxLength = Math.max(maxLength, right - left + 1).

This GitHub resource provides a clean JavaScript implementation of this logic.

Pattern 01 : Sliding Window.md

This resource provides concise code for several sliding window problems. It's a great reference to see the pattern implemented.

Please review the sections 'Longest Substring with K Distinct Characters (medium)' and 'Fruits into Baskets (medium)'. Notice how the code structure for both is nearly identical, reinforcing the power of the pattern.


4. Application 2: Finding the Minimum Window

The pattern can also be adapted to find the shortest or minimum window that satisfies a condition. The template logic is slightly inverted.

Here, we expand until the condition is met, then shrink as much as possible while it remains met, updating our minimum length inside the shrinking loop.

The canonical problem for this is "Minimum Window Substring" (LeetCode 76), a notoriously difficult but common FAANG interview question. Acing this demonstrates a deep understanding of the sliding window pattern.

Minimum Window Substring - Airbnb Interview Question - Leetcode 76

NeetCode offers a brilliant explanation of this problem. The key insight is using two maps and two counters, have and need, to efficiently track when the window contains all required characters. This avoids costly rescans.

Watch from 05:48 to 17:24. This is the core of the algorithm. The first part (until 10:31) explains how to expand the window and use the have and need counters to detect a valid window. The second part explains the crucial shrinking logic used to find the minimum possible length.

The logic for finding a minimum length window is:

  1. Expand the window by moving right until the condition is satisfied (e.g., have === need).
  2. Once satisfied, enter a while loop that shrinks the window from the left:
    • Update the minLength with the current window size.
    • Move left one step to the right.
    • Update the windowState.
    • The loop continues as long as the condition remains satisfied.
  3. When the condition is broken by shrinking, exit the inner loop and go back to step 1 (expanding).
Test your understanding!

You are solving "Minimum Size Subarray Sum" (find the smallest subarray with sum >= S).
Your array is [2, 3, 1, 2, 4, 3] and S = 7.
Your window is currently [2, 3, 1, 2]. The sum is 8 (>= 7). left=0, right=3. Your minLength is 4.

What is the very next step according to the "minimum window" template?

Show answer

The condition (sum >= 7) is met. Therefore, we try to shrink the window from the left.

  1. We record the current length (4) as a candidate for the minimum.
  2. We remove the leftmost element, arr[left] (which is 2), from the sum. The new sum is 6.
  3. We increment left. Now left=1.
  4. The new window is [3, 1, 2]. The sum is 6, which is now less than 7. The condition is violated.
  5. We exit the shrinking loop and continue expanding by moving the right pointer.

5. How to Recognize the Pattern

You're aiming to spot these patterns quickly in an interview. Here are some strong clues that a variable-size sliding window might be the answer.

Master the Sliding Window Technique

The 'Master the Sliding Window Technique' article we saw earlier has a great checklist for pattern recognition.

Read the section titled 'How to Recognize Variable Window Problems'. Internalize these keywords.

In summary, look for problems involving:

  • Contiguous arrays or substrings.
  • Finding the longest, shortest, maximum, or minimum subarray/substring.
  • Constraints like "at most K", "at least K", "contains all characters", or "sum >= target".

Conclusion

You've now learned the variable-size sliding window, a fundamental pattern for solving a huge class of array and string problems efficiently. By recognizing the problem type and applying the correct template (find maximum vs. find minimum), you can consistently turn a brute-force O(n²) problem into an optimal O(n) solution.

Key Takeaways:

  • The variable-size sliding window uses left and right pointers to define a dynamic window over a sequence.
  • The core mechanic is to expand the window with right and contract it with left based on whether a condition is met or violated.
  • For "longest/maximum" problems, you shrink when the condition is violated and update the result after every valid expansion.
  • For "shortest/minimum" problems, you expand until the condition is met, then shrink as much as possible while it remains met, updating your result inside the shrinking loop.
  • This pattern provides an optimal O(n) time and often O(k) or O(1) space solution.

Preview of the Next Lesson:
We will continue with the sliding window pattern, but focus on a specific, powerful variation: using a fixed-size window combined with a frequency map. This is perfect for problems like "Find All Anagrams in a String" and is a direct and logical next step in your journey to mastering these techniques. See you then