Files
leetcode/docs/(algorithms)/04-sliding-window.mdx
T

117 lines
3.4 KiB
Plaintext
Raw Normal View History

---
title: 'Sliding Window'
description: 'Two pointers plus incremental state between them.'
---
## The idea
Two pointers that move the **same direction**, carrying state between them.
Think of a caterpillar:
- The head crawls forward and eats (expand right).
- When the rule breaks, the tail pulls in until the rule holds again (contract left).
The window is always a **contiguous** slice. You never rebuild it — you update the carried state as edges move. That is what makes it O(n).
**The recipe:**
1. Expand right. Add the new element to your state.
2. Rule broken? Contract left until it holds.
3. Record the best window. Repeat.
## The picture
```mermaid
flowchart TD
A["a b c a b c<br/>[a] window = a"] --> B["[a b] expand → ab"]
B --> C["[a b c] expand → abc, best = 3"]
C --> D["a [b c a] 'a' repeats → contract, then expand"]
D --> E["a b [c a b] keep sliding, best stays 3"]
style C fill:#2e7d32,color:#fff
```
## Longest Substring Without Repeating (LC 3)
State = a set of chars in the window. Repeat found? Shrink from the left until it is gone.
```python
def length_of_longest_substring(s: str) -> int:
window = set()
left = 0
best = 0
for right, c in enumerate(s):
while c in window: # rule broken
window.remove(s[left]) # contract left
left += 1
window.add(c) # expand right
best = max(best, right - left + 1)
return best
```
## Best Time to Buy and Sell (LC 121) — the hidden window
Looks like a stock problem. It is a window problem.
Left = cheapest buy so far. Right = today. Carry one number: the min price.
```python
def max_profit(prices: list[int]) -> int:
min_price = prices[0]
best = 0
for p in prices[1:]:
best = max(best, p - min_price)
min_price = min(min_price, p)
return best
```
## Character Replacement (LC 424) — window with a budget
Rule: window is valid if `window size − count of top letter ≤ k`.
That many replacements fix the window. Carry a frequency map.
```python
from collections import defaultdict
def character_replacement(s: str, k: int) -> int:
count = defaultdict(int)
left = 0
best = 0
top = 0 # highest letter count seen
for right, c in enumerate(s):
count[c] += 1
top = max(top, count[c])
if (right - left + 1) - top > k: # over budget
count[s[left]] -= 1 # contract exactly one step
left += 1
best = max(best, right - left + 1)
return best
```
## When the window fails
Sliding window needs a one-way rule: **growing can only hurt, shrinking can only help.**
Negative numbers break this — a bigger window can flip from bad to good.
That is when you reach for prefix sum + hashmap (LC 560) instead.
Say this decision out loud in the interview.
## Complexity
| | Time | Space |
|---|---|---|
| All patterns above | O(n) — each index enters and leaves once | O(1) or O(alphabet) |
## Close-out ritual
Before you submit, say out loud:
1. Time and space complexity — note each element enters and leaves the window at most once.
2. One edge case trace: empty string, all same char, or k larger than the string.
## Plan problems
**A-set:** LC 121 · 3 · 424 · 567 · 76
**B-set:** LC 209 · 1004 · 643
<YouTube id="QGNAVBn1_bc" title="Sliding Window" />