Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Sliding Window Aggregates

Welcome to the second module of our course! In the previous module, we built a strong foundation in array and subarray manipulation, culminating in techniques like Kadane's algorithm for maximum sum subarrays and the two-pointer method for in-place partitioning. Today, we begin our exploration of another powerful and highly efficient pattern: the sliding window.

This lesson will introduce you to the first variant of this pattern. Your learning outcome is to implement a fixed-size sliding window to compute aggregates over contiguous subarrays. This technique is essential for solving a class of problems where you need to analyze a continuous block of elements of a specific length, such as finding the best-performing period in stock data or identifying the densest region in a data stream. We will focus on the core logic, its implementation, and how it dramatically improves efficiency.

The Problem: Redundant Calculations

Let's begin with a classic problem that exemplifies the need for a better approach: Given an array of integers and a number k, find the maximum sum of any contiguous subarray of size k.

For example, if arr = [2, 1, 5, 1, 3, 2] and k = 3, the subarrays of size 3 are:

  • [2, 1, 5] -> sum = 8
  • [1, 5, 1] -> sum = 7
  • [5, 1, 3] -> sum = 9
  • [1, 3, 2] -> sum = 6

The maximum sum is 9.

A straightforward, brute-force solution would be to generate every possible subarray of size k, calculate its sum, and keep track of the maximum sum found.

Maximum sum of a subarray of size k

This GeeksforGeeks article starts by explaining the brute-force method. It serves as a perfect baseline for understanding why we need a more optimized technique.

Please read the section titled "Naive Approach". Pay attention to the nested loops in the code. The outer loop selects the starting point of a subarray, and the inner loop sums up the k elements.

This brute-force method has a time complexity of because for each of the approximately possible starting positions, we perform additions. When N and k are large, this becomes very inefficient. The core issue is redundant work. When we slide our focus from [2, 1, 5] to [1, 5, 1], we recalculate the sum of 1 and 5, even though we just computed it. The sliding window technique is designed to eliminate this very inefficiency.

The Insight: Slide, Don't Recalculate

The key insight of the sliding window pattern is to maintain a "window" of k elements and, as we slide it across the array, update our calculation in constant time, , for each step.

Instead of recalculating the sum of the entire new window, we can get the new sum by:

  1. Subtracting the element that is sliding out of the window (the leftmost element).
  2. Adding the element that is sliding into the window (the new rightmost element).

This simple update maintains the sum of the current window of k elements as we move it one position at a time. The following video explains this crucial optimization.

Sliding Window Technique

This video from Profound Academy provides a clear, conceptual explanation of how the sliding window avoids redundant calculations.

Watch the segment from the explanation where the presenter contrasts the re-summing approach with the optimized method of subtracting the outgoing element and adding the incoming one.

This process is visualized perfectly in the image below. We calculate the sum of the first window [5, 3, 4] which is 12. To get the sum of the next window, we don't re-sum 3, 4, 6. Instead, we take the previous sum (12), subtract the outgoing element (5), and add the incoming element (6).

currSum = 12 - 5 + 6 = 13

This diagram demonstrates the fixed-size sliding window in action. The window of size k=3 slides to the right. At each step, the `currSum` is efficiently updated by subtracting the element leaving the window and adding the new element entering it. The `maxSum` is updated whenever `currSum` exceeds its current value.

By doing this, we reduce the work at each step from additions to just one subtraction and one addition. Since we do this for all possible windows, the total time complexity becomes .

Implementation and a General Template

Now that you grasp the concept, let's translate it into code. We'll examine a closely related problem, LeetCode 643: "Maximum Average Subarray I". The goal is to find the maximum average of a subarray of size k. This is equivalent to finding the maximum sum and then dividing by k, so the core logic is identical.

Sliding Window in 7 minutes | LeetCode Pattern

This video from AlgoMasterIO walks through the "Maximum Average Subarray I" problem, applying the fixed-size sliding window pattern.

Watch the explanation of the problem and optimization, where the brute-force approach is contrasted with the efficient sliding window solution. Then, follow the code walkthrough to see how this logic is implemented.

The structure of this solution can be generalized into a template that you can adapt for any fixed-size sliding window problem. The main components are:

  • A start pointer for the beginning of the window.
  • An end pointer that expands the window.
  • A variable (state) to hold the aggregate value of the current window (e.g., current_sum).
  • A variable to track the overall best result found so far (e.g., max_sum).

Fixed Length Sliding Window

The Hello Interview article provides an excellent, clean Python implementation and a general template.

Focus on the Python code in the Solution section. Notice how the loop uses end to iterate through the array. The if condition end - start + 1 == k is the key: it triggers the logic only when the window has reached the desired size. Inside the if block, the result is updated, and then the window slides by removing nums[start] and incrementing start.

A common pitfall during implementation is an off-by-one error, especially in defining loop boundaries. You must ensure your window correctly processes the entire array, including the very last possible window.

This image illustrates an off-by-one error. The top example's loop terminates too early, preventing the window from ever including the final element, `5`. The bottom example shows the correct implementation where the loop ensures all elements are considered.

To avoid this, a common pattern is to loop from i = k to n-1, where n is the array length. In each iteration, arr[i] is the new element entering the window, and arr[i-k] is the element leaving it. This simplifies pointer management.

Connection to Prefix Sums

You might recall the Prefix Sum technique from our first module. This is another way to solve the maximum sum problem. We could pre-compute a prefix sum array in time and space. Then, the sum of any subarray [i, j] can be found in time. We could iterate through all windows and find their sums this way.

Maximum sum of a subarray of size k

Let's revisit the GeeksforGeeks article to see this alternative approach.

Read the section titled "Using Prefix Sum". This method also achieves an O(N) time complexity but notice that it requires an auxiliary array for the prefix sums, leading to O(N) space complexity.

While both Prefix Sum and Sliding Window have time complexity for this problem, the sliding window approach is superior in terms of space complexity. It uses only a few variables to track the state, giving it an space complexity, which is often a critical advantage.

Conclusion

In this lesson, you've learned the fundamentals of the fixed-size sliding window technique. We started by identifying the inefficiency of the brute-force approach and then introduced the core insight of the sliding window: updating the window's aggregate value in constant time.

Key Takeaways:

  • The sliding window pattern is highly effective for problems involving contiguous subarrays or substrings.
  • The fixed-size variant is used when the problem specifies the exact length of the window (k).
  • The key optimization comes from subtracting the outgoing element and adding the incoming element, which updates the window's state in time.
  • This technique reduces the time complexity for many problems from to a much more efficient , typically with space.

You now have a solid template for tackling fixed-window problems. In our next lesson, we will build on this foundation to explore the variable-size sliding window. This more dynamic version involves expanding and shrinking the window to find subarrays that satisfy a condition, without a predetermined size.

Can't find a good explanation? Sign up and we'll make it for you

Sign up