← Back to section

Pattern 3: Sliding Window

When the question is about contiguous slices (windows) of the array, don't recompute each window from scratch: slide β€” update only what entered and what left.

🎯

Try it first: Best Time to Buy and Sell Stock

Before reading the theory, try to solve it. You can start with brute force, you can fail β€” the point is to feel the problem. The theory comes right below.

prices[i] is the price of a stock on day i. Choose a day to buy and a later day to sell, maximizing profit. If no profit is possible, return 0.

Example: prices = [7, 1, 5, 3, 6, 4] β†’ 5 (buy at 1, sell at 6).

Carregando editor…

Did you try? The brute force tests all (buy, sell) pairs β€” O(nΒ²). And, once again, it recomputes each day something that barely changed: the lowest price up to that point. The theory below shows how to carry that "state" instead of recomputing it.

The theory: what problem does sliding window solve?

Recognize the statements: "the largest subarray that...", "the smallest window containing...", "the sum of each slice of k days...". The keyword is contiguous β€” the elements of the answer are neighbors in the array.

The brute force tests every window: O(nΒ²) possible windows, and it still pays O(n) to evaluate each one β€” up to O(nΒ³)! The waste is glaring: window [i..j] and window [i+1..j+1] share almost all their elements, and the brute force recomputes everything as if it had never seen them.

The pattern's idea: treat the window as a living state. As you slide, one element enters from the right and one leaves from the left β€” update the state with those two O(1) touches and that's it: the new window is evaluated.

The two variants

Fixed window (size k given by the statement):

compute the state of the first window [0..k-1]
for right from k to n-1:
    state += entry of nums[right]
    state -= exit of nums[right - k]
    record the best

Variable window (looking for the largest/smallest window that satisfies a condition):

left = 0
for right from 0 to n-1:
    nums[right] enters the state
    while the state VIOLATES the condition:
        nums[left] leaves the state
        left += 1
    record the best (window [left..right] is valid)

Why is the variable window O(n) β€” and not O(nΒ²)?

The inner while is deceptive: it looks like a loop within a loop. But count it another way: each element enters the window exactly 1 time (right passes over it) and leaves at most 1 time (left passes over it). That's at most 2n pointer moves total, each with O(1) work. Total: O(n) β€” the same "irreversible progress" argument as two pointers (not by chance: sliding window IS two pointers moving in the same direction).

The signals in the statement

  • "Contiguous subarray/substring" + "largest/smallest/best".
  • Windows of fixed size k ("average of each k days").
  • A condition the window must satisfy ("at most k distinct characters", "sum β‰₯ target").
  • Careful: with negative numbers, "growing the window" might not increase the sum β€” then the sum-based sliding window fails and the right pattern changes (prefix, next lesson, or Kadane).

Example β€” Best Time to Buy and Sell Stock

"Given the stock price on each day, choose a day to buy and a later day to sell, maximizing profit."

  • Brute force: every (buy, sell) pair with the sale after the purchase β€” O(nΒ²).
  • The waste: for each sell day, the brute force re-searches for the lowest price in the past β€” which barely changed from one day to the next.
  • The pattern: slide the sell day (i) and carry as state the lowest price seen so far (min_price). Each day: profit if selling today = price - min_price; then update min_price.

It's a variable window where the state is a single number β€” the minimum of the window [0..i]. Watch the state being carried instead of recomputed:

ExecuΓ§Γ£o real, gravada passo a passo
Carregando Python no navegador (primeira vez demora alguns segundos)…

Why is it O(n)?

A single pass (n iterations), and the state updates with two O(1) comparisons per iteration β€” because the prefix minimum is incremental: the minimum up to today is min(minimum up to yesterday, today's price). n Γ— O(1) = O(n) time, O(1) space (the state is two variables).

SolutionTimeSpaceWhy
Brute forceO(nΒ²)O(1)all buy/sell pairs
Window with running minimumO(n)O(1)incremental state, 1 pass

The template in action: fixed window

To cement the enter/exit mechanics, a classic example: largest sum of a window of k elements. Notice the two lines that do all the magic β€” with no recomputation:

Carregando editor…

Where the pattern shows its full strength

Sliding window really shines in the String section: Longest Substring Without Repeating Characters (variable window + hash set as state), Minimum Window Substring (variable window + count map). The state gets richer, but the skeleton is exactly the template from this lesson β€” whoever masters the template here gets there just by swapping the state.

🧠 Review quiz

0/4

1. What is the waste that sliding window eliminates?

2. In the variable window there's a while inside a for. Why is it still O(n)?

3. Why does the sum-based sliding window FAIL with negative numbers (e.g. 'largest sum of any subarray')?

4. In Best Time to Buy and Sell Stock, what is the 'state' the window carries and why does it update in O(1)?

Summary

  • Signals: contiguous subarray/substring + largest/smallest/condition.
  • The window is a living state: one element enters, one leaves, O(1) per step.
  • Variable window: right expands, left shrinks when the condition is violated β€” O(n) because each element enters/leaves at most 1 time.
  • Negatives break the monotonicity of the sum β†’ use prefix (lesson 5) or Kadane (lesson 6).

Next lesson: what about when the windows that matter are not neighbors? Precompute everything β€” prefix and suffix.