AniUI Academy

Sliding Window

Avoid recomputing overlapping work by growing and shrinking a window over an array or string in one pass — fixed-size sums, longest-substring problems, and a real debounce framing.

10 min read

Sliding window is two pointers' close cousin, specialized for a specific shape of problem: "look at every contiguous run of size k" or "find the longest/shortest contiguous run satisfying some condition." The naive approach recomputes each run from scratch. The sliding window approach notices that consecutive runs overlap almost entirely, and updates incrementally instead of recomputing.

Fixed-size window: maximum sum of k consecutive elements

function maxSumOfSizeK(arr, k) {
  let windowSum = 0;
  for (let i = 0; i < k; i++) windowSum += arr[i]; // first window, computed once
 
  let maxSum = windowSum;
 
  for (let end = k; end < arr.length; end++) {
    windowSum += arr[end] - arr[end - k]; // add the new element, remove the one that fell out
    maxSum = Math.max(maxSum, windowSum);
  }
 
  return maxSum;
}

The naive version would sum k elements at every one of roughly n positions — O(n * k). This version computes the first window's sum once, then updates it in O(1) per step by adding exactly one new element and subtracting exactly one departing element. Total: O(n) time, O(1) auxiliary space. This is the same "maintain a running total instead of recomputing" idea behind the prefix-sum technique two lessons from now, applied to a moving range instead of a fixed one from the start.

Variable-size window: longest substring without repeating characters

Fixed windows have a known size. Variable windows grow and shrink based on a condition — and this is where sliding window earns its reputation as the pattern behind a large share of real string problems:

function longestUniqueSubstring(str) {
  const seen = new Set();
  let left = 0;
  let longest = 0;
 
  for (let right = 0; right < str.length; right++) {
    while (seen.has(str[right])) {
      seen.delete(str[left]);
      left++;
    }
    seen.add(str[right]);
    longest = Math.max(longest, right - left + 1);
  }
 
  return longest;
}

Walk through the logic: right extends the window by one character every step. If that character is already in the window (seen.has(...)), the window can't grow past it while staying duplicate-free — so left advances, removing characters from the window, until the duplicate is gone. Only then does the new character get added and the window's length gets checked against the best seen so far.

The subtlety that makes this O(n) rather than O(n²): although there's a while loop nested inside a for loop, left only ever moves forward and never resets. Across the entire run of the algorithm, left makes at most n total moves and right makes exactly n moves — 2n total pointer steps, not n * n. This is the same monotonic-pointer argument from the two-pointers lesson, applied to a window instead of two independent ends.

  1. Step 1

    right at 'a', 'b', 'c'

    Window = "abc", no duplicates yet, longest = 3.

  2. Step 2

    right at second 'a'

    'a' is already in the window. left advances past it, removing 'a' from the set.

  3. Step 3

    Window becomes "bca"

    No duplicates now — add the new 'a', longest stays 3.

  4. Step 4

    Continue to the end

    The same shrink-then-grow logic repeats; longest never exceeds 3 for this input.

Growing and shrinking the window for 'abcabcbb' — right always advances; left only advances to remove a duplicate.

A real frontend framing: a live-typing character limit

Sliding window isn't just for interview strings. A "no more than N unique tags in the visible filter chips" feature, or a live text area that highlights the longest run of non-repeating characters as a typing-quality indicator, is literally this algorithm running on real user input, not a contrived example.

Try it yourself
Loading playground...

What to remember

  • Fixed-size sliding window avoids recomputing overlapping sums by updating a running total: add what entered, subtract what left. O(n * k) becomes O(n).
  • Variable-size sliding window grows the right edge greedily and only shrinks the left edge when a condition (like "no duplicates") would otherwise be violated.
  • The reason a nested-looking window is still O(n) overall: both pointers are monotonic — each only moves forward, for a bounded total of roughly 2n moves across the whole run, not n².
  • This pattern is the conceptual backbone of debouncing (covered later in this course) — a window that keeps extending while events arrive and resolves once they stop.

Check yourself

4 questions · pass 3/4 to unlock In-Place Array Manipulation

up to 50
  1. 1.A naive solution to "find the maximum sum of any 5 consecutive elements" recomputes the sum of all 5 elements at every starting position. What is its time complexity, and why does the fixed-size sliding window beat it?

  2. 2.In the variable-size "longest substring without repeating characters" pattern, what causes the left edge of the window to move forward?

  3. 3.Why is the variable-size sliding window over a string of length n still considered O(n) overall, even though there's a loop for the right edge and a loop (or while) for the left edge?

  4. 4.A search-as-you-type feature buffers keystrokes and only fires a request once no new keystroke has arrived for 300ms. Which sliding-window idea does this most resemble?

4 left to answer