Skip to content
DSA patterns 7 min read

The Sliding Window Pattern: Template & When to Use It

The sliding window pattern turns an O(n·k) or O(n²) scan over contiguous subarrays or substrings into a single O(n) pass by maintaining a moving “window” [left, right] and updating a running summary as the window slides instead of recomputing it from scratch. This page recaps when to reach for it and gives templates for both window types.

For the full topic treatment, see sliding window: introduction.

The signal: when to recognize it

The pattern almost always involves a contiguous run of elements. Look for these phrases:

  • Subarray / substring” (contiguous) — not “subsequence” (which can skip elements; that’s usually DP).
  • Longest / shortest / maximum / minimum” run satisfying a condition.
  • At most k distinct / exactly k / sum equals / sum at least.”
  • A fixed window size is given (“every window of size k”).

For beginners: The whole trick is don’t recompute. When the window moves right by one, you add one new element’s contribution and remove one old element’s — O(1) per step instead of rescanning the window.

Template: fixed-size window

When the window size k is given, slide a window of exactly k and track its summary (here, the maximum sum of any window of size k).

#include <vector>
#include <algorithm>
// Fixed window: maximum sum of any contiguous subarray of size k.
long maxSumWindow(const std::vector<int>& a, int k) {
    long windowSum = 0;
    for (int i = 0; i < k; i++) windowSum += a[i];   // first window
    long best = windowSum;
    for (int right = k; right < (int)a.size(); right++) {
        windowSum += a[right] - a[right - k];        // slide: add new, drop old
        best = std::max(best, windowSum);
    }
    return best;
}

Template: variable-size window

When the size isn’t fixed, grow the window by moving right, and shrink from left whenever the window breaks a constraint. This finds the longest substring with no repeated characters.

#include <string>
#include <unordered_map>
#include <algorithm>
// Variable window: length of the longest substring without repeating characters.
int longestUnique(const std::string& s) {
    std::unordered_map<char, int> lastSeen;
    int left = 0, best = 0;
    for (int right = 0; right < (int)s.size(); right++) {
        char c = s[right];
        if (lastSeen.count(c) && lastSeen[c] >= left)
            left = lastSeen[c] + 1;        // shrink past the duplicate
        lastSeen[c] = right;
        best = std::max(best, right - left + 1);
    }
    return best;
}

Complexity

Both templates are O(n) time: right advances n times, and left only ever advances (it never moves backward), so total pointer movement is bounded by 2n. Space is O(1) for the fixed-sum version and O(k) (the distinct elements in the window) for the variable version that tracks counts.

Common pitfalls

  • Using it on non-contiguous problems. “Subsequence” is not a window — that’s usually dynamic programming.
  • Shrinking with if vs while. For “at most k” constraints you often need a while loop to shrink until the window is valid again.
  • Stale running summary. When you move left, you must subtract the leaving element’s contribution.

Going deeper: Prefix sums solve some “sum equals k” window problems even when values can be negative — a case the shrink-on-overflow window can’t handle.

Practice

Drill it in the sliding window exercises. Compare with the two-pointers pattern: both walk two indices, but a window keeps everything between them as the answer candidate.

Last updated June 25, 2026
Was this helpful?