On this page
Description
A sliding window is a contiguous range of an array or string that moves forward one step at a time. It carries a running summary of what's inside it: a sum, a count, or a map of how often each value appears. Instead of recomputing that summary for every range, you add the element that enters and remove the one that leaves. It answers "best contiguous range" questions, such as the largest sum of k values in a row, the longest substring without repeats, or the shortest subarray that reaches a target.
We'll go from simple to more technical:
- The fixed-size window: one add and one subtract per step.
- The variable-size window:
rightalways advances,leftcatches up. - Where the same idea runs in production (rate limiters, moving averages).
- When it applies, and the mistakes that make the window drift.
The approach (fixed-size window)
The brute force adds up every window from scratch: k additions for each of the n - k + 1 windows, O(n*k) in all. But two neighboring windows share all but two elements. So keep one running sum. Each step adds the element that enters on the right and, once the window is full, subtracts the one that leaves on the left.
The largest sum of 3 values in a row in [3, 1, 4, 2, 5, 1]:
| i | Enters | Leaves | Window | Sum | Best |
|---|---|---|---|---|---|
| 0 | 3 | [3] | 3 | ||
| 1 | 1 | [3, 1] | 4 | ||
| 2 | 4 | [3, 1, 4] | 8 | 8 | |
| 3 | 2 | 3 | [1, 4, 2] | 7 | 8 |
| 4 | 5 | 1 | [4, 2, 5] | 11 | 11 |
| 5 | 1 | 4 | [2, 5, 1] | 8 | 11 |
Java
int windowSum = 0;
for (int i = 0; i < nums.length; i++) {
windowSum += nums[i];
if (i >= k) windowSum -= nums[i - k]; // drop the element leaving the window
if (i >= k - 1) best = Math.max(best, windowSum);
}
Python
window_sum = 0
for i in range(len(nums)):
window_sum += nums[i]
if i >= k:
window_sum -= nums[i - k] # drop the element leaving the window
if i >= k - 1:
best = max(best, window_sum)
The window is never rescanned. Each step does one add and, once the window is full, one subtract. That turns O(n*k) into O(n).
A second flavor: variable-size windows
Some questions have no fixed size. "The shortest subarray with a sum of at least the target" needs a window that grows and shrinks:
Java
int left = 0, sum = 0, best = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right]; // right always advances
while (sum >= target) { // left advances only while the condition holds
best = Math.min(best, right - left + 1);
sum -= nums[left];
left++;
}
}
Python
left = total = 0
best = float("inf")
for right in range(len(nums)):
total += nums[right] # right always advances
while total >= target: # left advances only while the condition holds
best = min(best, right - left + 1)
total -= nums[left]
left += 1
right moves one step per loop, as before. left moves zero, one or several steps, as long as the window still meets the condition. So the two edges no longer move together. For [1, 4, 2, 2, 5, 1] and a target of 7, the shortest window is [2, 5], of length 2. Each element enters once and leaves at most once, so this is still O(n).
Where you'll see it
A rate limiter works this way. "How many requests in the last 60 seconds?" is a window over a stream of timestamps, updated as requests arrive instead of recounted each time. A dashboard's rolling 5-minute average latency is computed the same way, without rereading the whole buffer every tick.
Which tool for which job?
| You need | Use |
|---|---|
| Something about every window of exactly k elements | a fixed-size window |
| The shortest or longest range meeting a condition | a variable-size window |
| A subarray sum with negative numbers allowed | prefix sums with a hash map (next skill) |
| The maximum or minimum of every window | a monotonic deque |
| The median of every window | two heaps (O(log k) per step) |
| "Exactly K" of something | at most K minus at most K - 1 |
Common mistakes
| Mistake | What happens | Do this instead |
|---|---|---|
i > k instead of i >= k | one element is never removed; every answer is off | trace k = 1 by hand |
| A set where duplicates can be in the window | removing one copy forgets the others | a frequency map: decrement, delete at 0 |
| Shrinking a sum window when values can be negative | answers are missed | prefix sums instead |
| A plain variable for the window maximum | wrong once the max leaves | a monotonic deque |
if instead of while when shrinking | the window stays invalid | shrink in a loop until it's valid |
Check yourself
Try to answer before opening each one - recalling beats re-reading.
1. A fixed-size window checks i > k instead of i >= k. What goes wrong?
Show answer
The subtraction due at i = k, which removes nums[0], never happens. Later steps subtract nums[1], nums[2] and so on as usual, but nums[0] stays in the sum forever. From i = k on, every sum is the right window's sum plus a stale nums[0].
2. Why can't a variable-size window move left by a fixed amount when the window stops meeting the condition?
Show answer
How far left must move depends on the data. One step may not be enough, and a fixed bigger step can skip past the best window. So left moves one step at a time in its own loop, checking the condition after each step.
3. You need the maximum of every window of size k. Can it be updated cheaply as the window slides?
Show answer
Not with a plain variable. When the maximum leaves the window, you'd have to rescan to find the next one. A monotonic deque fixes that: it keeps only the values that could still become the maximum, in decreasing order, for amortized O(1) per step. Some summaries need a smarter structure before they can slide.
Key takeaways
- A fixed-size window adds the element that enters and subtracts the one that leaves: O(n) instead of O(n*k).
- In a variable-size window,
rightmoves every step andleftmoves only while the window still meets the condition. - The most common bug is an off-by-one at the window's edge. Trace k = 1 by hand.
- Whatever you did when an element entered, undo exactly when it leaves (decrement a count, don't just remove from a set).
- The idea only pays off when the summary can be updated more cheaply than recomputed.