一键导入
algo-sliding-window
Sliding window — fixed and variable size, expand-shrink invariant, hash-state-tracking for substring problems.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Sliding window — fixed and variable size, expand-shrink invariant, hash-state-tracking for substring problems.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups.
Binary search invariants, half-open intervals, and the `lo<hi` template that beats off-by-one bugs.
Depth-first search — recursive vs iterative, recursion-depth gotchas, three-color cycle detection, topological sort.
Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool.
Pick the right traversal — BFS for unweighted shortest path, Dijkstra for weighted, A* for goal-directed, 0/1-BFS for binary weights.
Greedy algorithms — exchange-argument proofs, when greedy beats DP, classic patterns (interval scheduling, Huffman, scheduling).
| 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 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.
[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.O(n) amortised — each element is pushed once and popped
at most once across the whole scan.O(k) for the state (e.g., a counter dict for distinct
characters).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.
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.
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.
while > k),
not after one step (if > k). Off by one breaks "longest".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").counts[c] == 0 linger inflates
len(counts) and breaks the constraint check. Delete on zero.if len(arr) < k.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.