Skip to main content

Welcome to a Grasp lesson

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

Lesson 14

Sliding Window Technique for Subarray/Substring Problems

Recommended resources

Hello! Welcome back to our third module, "High-ROI Interview Patterns."

In our previous lessons, we've focused on pointer manipulation in linked lists, mastering techniques like fast/slow pointers and iterative reversal. These are crucial for handling sequential data stored in non-contiguous memory.

Today, we shift our focus back to arrays and strings to learn another powerful, high-ROI pattern: the sliding window. This technique is your go-to for problems that ask you to find a sub-array or substring that satisfies a certain condition. The key insight is to avoid redundant calculations by intelligently "sliding" a window of consideration across the data, which almost always reduces a brute-force O(n²) solution to an optimal O(n) one. For your interview preparation, mastering this pattern is essential.

Our goal is to apply the sliding window pattern to solve array and string subarray/substring problems. We will cover the two main variations: fixed-length and variable-length windows.

1. The Sliding Window: A Conceptual Overview

At its core, the sliding window pattern is about maintaining a "window" (a contiguous sub-array or substring) and moving its endpoints through the larger data structure. Instead of re-computing the properties of every possible subarray from scratch, you update the window's state by adding an element at one end and, when necessary, removing an element from the other.

Sliding Window Technique Illustration
This image illustrates a fixed-size window sliding across an array. As the window moves right, a new element is included, and an old one is excluded. The sum is updated efficiently rather than being recalculated from scratch, which is the essence of the sliding window's O(n) performance.

There are two main types of sliding window problems, and identifying which type you're dealing with is the first step to a solution.

Sliding Window Algorithm - Variable Length + Fixed Length - DSA Course in Python Lecture 13

To start, watch this brief introduction from the 'Sliding Window Algorithm' video by Greg Hogg. It clearly defines the two fundamental types of sliding windows: fixed-length and variable-length.

Watch the first minute of the video (00:00 to 00:57). Pay close attention to the cues that suggest a problem might be solvable with a sliding window, such as the mention of 'subarrays' or 'substrings'.


2. Fixed-Length Sliding Window

This is the simpler of the two patterns. You use it when the problem specifies a fixed size, k, for the subarray or substring you're interested in.

The logic is straightforward:

  1. Create an initial window of size k.
  2. Calculate the desired metric (e.g., sum, average, character count) for this first window.
  3. Slide the window one element at a time until you reach the end of the array.
  4. In each slide, add the new element that enters the window and subtract the element that leaves the window. This O(1) update is far more efficient than re-calculating everything.
  5. Update your global answer at each step.

The article "Fixed Length Sliding Window" from HelloInterview provides an excellent textual explanation and a clean template.

Fixed Length Sliding Window

Let's walk through a classic example: finding the maximum sum of a subarray of a given size k.

Read the sections 'Fixed-Length Sliding Window', 'Problem: Maximum Sum of Subarray with Size K', and the 'Template'. Focus on how the state (the current sum) is efficiently updated by adding nums[end] and subtracting nums[start] in each step.

Fixed-Length Template

As you saw in the article, the structure for a fixed-length window is very consistent. Here is the general template you can adapt:

def fixed_length_sliding_window(arr, k):
    # Initialize pointers and state
    start = 0
    current_window_state = ... # e.g., a sum, a hash map
    result = ...

    for end in range(len(arr)):
        # Update state by adding the new element arr[end]
        update_state_add(arr[end])

        # Once the window reaches size k, start sliding
        if (end - start + 1) == k:
            # 1. Process the current window, update result
            update_result(current_window_state)

            # 2. Update state by removing the old element arr[start]
            update_state_remove(arr[start])

            # 3. Slide the window forward
            start += 1
    
    return result

3. Variable-Length Sliding Window

This pattern is more dynamic and powerful. You use it when the window size isn't fixed but must conform to some property (e.g., "contains no more than 2 distinct characters," or "has a sum less than a target").

The general logic involves two pointers, start and end, and a while loop nested inside a for loop:

  1. The end pointer expands the window by moving to the right, one element at a time.
  2. At each step, you add the new element to your window's state.
  3. After adding the new element, you check if the window's state is still valid.
  4. If the window is invalid, you enter a while loop that shrinks the window from the left by moving the start pointer to the right until the window becomes valid again.
  5. After ensuring the window is valid, you can update your answer (e.g., record the maximum length found so far).

"Longest Substring Without Repeating Characters" is the quintessential variable-length sliding window problem. Let's see a detailed walkthrough.

Sliding Window Algorithm - Variable Length + Fixed Length - DSA Course in Python Lecture 13

This part of Greg Hogg's video provides an excellent, step-by-step walkthrough of solving 'Longest Substring Without Repeating Characters'.

Watch from 00:57 to 12:32. Focus on the core logic: when is the window considered 'invalid'? How is the window shrunk using the left pointer (L) and a set to restore validity? This dynamic expansion and contraction is the key to this pattern.

Variable-Length Template

The key to this pattern is the while loop that contracts the window. The resource from HelloInterview provides a great template for this logic.

Variable Length Sliding Window

To solidify your understanding, review this article on variable-length windows. It provides a clean template that generalizes the expand-and-contract logic.

Focus on the 'Template' section. Notice the structure: a for loop to expand (end) and a nested while loop to contract (start) based on a validity check.

This gives us the following general structure:

def variable_length_sliding_window(arr):
    start = 0
    result = ...
    current_window_state = ...

    for end in range(len(arr)):
        # 1. Expand the window by including arr[end]
        update_state_add(arr[end])

        # 2. While the window is invalid, contract it from the left
        while not is_window_valid(current_window_state):
            update_state_remove(arr[start])
            start += 1
        
        # 3. Now the window is valid. Update the result.
        #    (e.g., max_length = max(max_length, end - start + 1))
        update_result(...)

    return result
Test your understanding!

You are given the problem: "Given a string s and an integer k, find the length of the longest substring of s that contains at most k distinct characters."

Would you use a fixed-length or variable-length sliding window? Briefly outline the state you would maintain and the invalid condition for the window.

Show answer

This calls for a variable-length sliding window because the length of the substring is what we are trying to maximize, not a fixed input.

  • State: A hash map (dictionary in Python) to store the frequency of characters currently in the window. {'char': count}.
  • Invalid Condition: The window becomes invalid if the number of unique keys in the hash map is greater than k (i.e., len(char_frequency_map) > k).
  • Logic: You would expand the window with the end pointer. If len(char_frequency_map) exceeds k, you would shrink the window from the start, decrementing character counts in the map and removing characters with a count of zero, until len(char_frequency_map) is back to k or less. At each valid step, you'd update max_length = max(max_length, end - start + 1).

4. How to Spot a Sliding Window Problem

Recognizing when to use this pattern is half the battle. Here are some strong cues to look for in a problem description:

  • Input: The problem involves a linear data structure like an array, linked list, or string.
  • Output: You are asked to find the longest/shortest/maximum/minimum value of a contiguous subarray or substring.
  • Keywords: Look for phrases like "subarray," "substring," "contiguous," "min/max length," "at most k," etc.

For a rapid-fire summary of these cues and more examples, the following video is helpful.

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

This video by Nikhil Lohia provides a great summary of how to identify sliding window problems and recaps the core ideas with several examples.

Watch the sections from 13:12 to 14:47 and from 22:06 to 24:54. These parts summarize the problem characteristics that signal a sliding window solution and recap the components of the pattern.


Conclusion

You've now added another powerful, optimal pattern to your interview toolkit. The sliding window technique elegantly transforms brute-force problems into linear-time solutions, a trade-off that interviewers love to see.

Key Takeaways:

  • Core Idea: The sliding window pattern processes arrays or strings by maintaining a "window" and sliding it across the data, updating a state incrementally rather than re-computing from scratch. This reduces time complexity from O(n²) to O(n).
  • Fixed-Length Window: Use when the problem specifies a subarray/substring of a fixed size k. The logic involves adding the end element and removing the start element in each step.
  • Variable-Length Window: Use when the window must satisfy a certain property and its size is not given. The logic involves expanding with an end pointer and contracting with a start pointer whenever the property is violated.
  • Problem Recognition: Look for problems involving contiguous subarrays/substrings on linear data structures, especially those asking for a min/max value under certain constraints.

In our next lesson, we will explore another technique for efficiently handling array problems: prefix sums. This method is perfect for answering range query problems in O(1) time after an initial O(n) preprocessing step.