Skip to content
Back to skills

Sliding Window

ASecurity

Sliding window — fixed and variable size, expand-shrink invariant, hash-state-tracking for substring problems.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added August 31, 2026
ai-agentsjavascriptpythongojava

Security analysis

A100/100

Scanned August 31, 2026

npx -y skills add 0bserver07/chimera --skill sliding-window --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sliding Window?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sliding Window
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/0bserver07-sliding-window/badge)](https://www.skillsdirectory.com/skills/0bserver07-sliding-window)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: algo-sliding-window
description: Sliding window — fixed and variable size, expand-shrink invariant, hash-state-tracking for substring problems.
when-to-use: "Longest/shortest substring with constraint, k-distinct elements, max sum subarray of size k, anagram windows."
---

## Sliding window — expand right, shrink left

Sliding window collapses an `O(n^2)` "try every subarray" loop
into `O(n)` by reusing partial state across moves. The trick: the
window is *contiguous* and you keep enough state about the window
to update it in `O(1)` (or `O(k)` for `k` distinct keys) per step.

### Invariants

* The window `[l, r]` is contiguous — no skipping.
* `r` advances by 1 each outer iteration.
* `l` advances *only* when the window state violates the constraint.
  Once advanced, it never moves back.
* `state(window)` is maintained incrementally: add `arr[r]` on
  expand, subtract `arr[l]` on shrink.

### Complexity

* Time: `O(n)` amortised — each element is pushed once and popped
  at most once across the whole scan.
* Space: `O(k)` for the state (e.g., a counter dict for distinct
  characters).

### Template — Python (variable-size, longest substring with k distinct chars)

```python
def longest_k_distinct(s: str, k: int) -> int:
    """Length of the longest substring with at most k distinct characters."""
    from collections import Counter
    counts: Counter[str] = Counter()
    best = l = 0
    for r, ch in enumerate(s):
        counts[ch] += 1
        while len(counts) > k:
            counts[s[l]] -= 1
            if counts[s[l]] == 0:
                del counts[s[l]]
            l += 1
        best = max(best, r - l + 1)
    return best
```

The shrink loop keeps the invariant `len(counts) <= k`. The
`del` is critical — without it, `counts` keeps stale zeroes and
the `len` check fails.

### Template — Python (fixed-size window, max sum)

```python
def max_sum_subarray(arr: list[int], k: int) -> int:
    """Maximum sum over any contiguous subarray of length k."""
    if len(arr) < k: return 0
    s = sum(arr[:k])
    best = s
    for r in range(k, len(arr)):
        s += arr[r] - arr[r - k]   # roll the window
        best = max(best, s)
    return best
```

For fixed-size windows, the "subtract the leaver, add the joiner"
trick eliminates the inner loop entirely.

### Template — JavaScript (anagram-window detection)

```javascript
function findAnagrams(s, p) {
  if (p.length > s.length) return [];
  const need = new Map();
  for (const c of p) need.set(c, (need.get(c) || 0) + 1);
  const have = new Map();
  const out = [];
  for (let r = 0; r < s.length; r++) {
    const c = s[r];
    have.set(c, (have.get(c) || 0) + 1);
    if (r - p.length >= 0) {
      const left = s[r - p.length];
      have.set(left, have.get(left) - 1);
      if (have.get(left) === 0) have.delete(left);
    }
    // Compare maps by size + entries.
    if (have.size === need.size &&
        [...need].every(([k, v]) => have.get(k) === v)) {
      out.push(r - p.length + 1);
    }
  }
  return out;
}
```

The window slides by exactly one each step; comparison is `O(σ)`
where `σ` is the alphabet size — for ASCII, effectively constant.

### Common pitfalls

* **Shrinking too aggressively.** Some problems want the shrink
  to stop the moment the constraint is repaired (`while > k`),
  not after one step (`if > k`). Off by one breaks "longest".
* **Forgetting to update the answer at every `r`.** "Longest"
  problems update inside the outer loop, after the shrink. "Number
  of substrings" updates differently (count `r - l + 1` after
  shrink — see "subarrays with at most k distinct").
* **Stale zero counts.** Letting `counts[c] == 0` linger inflates
  `len(counts)` and breaks the constraint check. Delete on zero.
* **Negative numbers + monotonic shrink.** Sliding window on
  arbitrary signs *does not* always work — adding a negative
  number can shrink the sum, breaking the monotone-shrink
  property. Consider prefix-sum + monotonic queue / deque instead.
* **Fixed-window length larger than input.** Guard with
  `if len(arr) < k`.

### Test corner cases

* Empty input / k larger than n.
* k == 0 (degenerate — define behaviour explicitly).
* All-same characters.
* Alphabet larger than string length.
* Window straddling the very end of the input.
* "At most k distinct" with k == n (whole string is the window).

If the constraint is "at most k of X", sliding window is usually
the right tool. If the constraint involves a non-monotonic
function, reach for prefix-sum + monotonic deque instead.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.