Optimise a DP whose transition is a minimum or maximum over a sliding window:

from to , using a monotonic deque.

The sliding window minimum

Keep a deque of indices whose dp values are increasing. Before pushing , pop everything at the back with a value — those can never be the minimum again, because is both newer and better. Before querying, pop the front while it has fallen out of the window.

deque<int> dq;
for (int i = 0; i <= n; i++) {
    while (!dq.empty() && dq.front() < i - k) dq.pop_front();     // out of window
    dp[i] = (i == 0) ? 0 : dp[dq.front()] + cost(i);
    while (!dq.empty() && dp[dq.back()] >= dp[i]) dq.pop_back();  // dominated
    dq.push_back(i);
}

Each index enters and leaves the deque once, so the total work is .

When the window is not a fixed width

The technique needs only that the valid range of is a contiguous interval that moves monotonically with . Common cases:

Condition on Window
fixed width
two pointers determine the left end
(sorted )two pointers
where lastBad is non-decreasingtwo pointers

If the left end can move backwards, the deque is invalid — use a segment tree () or a different optimisation.

Adding a term that depends on

If the transition is , store in the deque instead of . The deque only needs the quantity being minimised to be computable at push time.

If instead the term couples and multiplicatively, the deque fails and you want CHT:

Transition shapeTechnique
over a windowmonotone queue,
over a windowmonotone queue,
CHT
, MongeD&C DP
over an arbitrary rangesegment tree,

Classic uses

Jump game with a bounded jump. dp[i] = min(dp[j]) + cost(i) for — the textbook case.

Bounded knapsack in . Group weights by residue class mod ; within each class the transition is a sliding-window maximum of over . This is how bounded knapsack achieves instead of — see Knapsack.

Maximum subarray with a length limit. max(pref[i] - min(pref[j])) over a window.

Constrained partitioning. “Split the array into pieces of length between and , minimising the total cost” — the window is .

The standalone structure

Sliding window minimum is useful outside DP too — see Monotonic Queue. It is also the -amortized way to implement a minimum queue, which is what makes Mo’s algorithm variants and certain graph algorithms fast.

Debugging checklist

  1. Is the window’s left end monotone non-decreasing? If not, the deque is wrong.
  2. Are you popping the front before querying and the back before pushing?
  3. Is the comparison >= (keeping the newest among equals) rather than >? Either is correct for the value, but >= keeps the deque shorter.
  4. Is dp[i] pushed after it is computed? Pushing before creates a self-dependency.

See also: Monotonic Queue · Convex Hull Trick · Knapsack