Direct answer: use a Sliding Window when the answer concerns a contiguous subarray or substring and you can update its state by adding the new right-side element and removing the old left-side element. Rather than recomputing every interval, maintain one moving range [left, right]. A fixed-size window advances after exactly k elements; a variable-size window expands until a condition fails or succeeds, then contracts only as much as necessary. In many problems each element enters and leaves once, producing O(n) time.
The essential question is not “does the prompt say longest?” It is “can I summarize the current contiguous range with a state such as a sum, frequency map, distinct count, or deque, and can I repair that state by moving the left boundary forward?” If the answer is yes, sliding window is a strong candidate.
Pattern Recognition Signals and Anti-Signals
| Signal | Likely state | Example |
|---|---|---|
| Exactly k consecutive items | Running sum, counts, or a monotonic deque | Maximum Average Subarray I, Find All Anagrams |
| Longest contiguous range satisfying a limit | Frequency map, distinct count, or running total | Longest Substring Without Repeating Characters |
| Shortest range covering a requirement | Required counts and a measure of coverage | Minimum Window Substring |
| At most or exactly K categories | Map plus number of distinct keys | Subarrays With K Different Integers |
| Maximum or minimum for every k-length range | Monotonic deque of useful indices | Sliding Window Maximum |
Anti-signals: “subsequence” means elements need not be adjacent, so a window is usually wrong. An arbitrary subset is not a window. A target-sum problem containing negative numbers can break the monotonic reasoning behind the usual “shrink while sum is large enough” template. If the input is sorted and the task is a pair relationship rather than a contiguous interval, use Two Pointers instead. If the problem branches into repeated choices and asks for an optimum or count across states, examine Dynamic Programming.
The Window Invariant and State
Define the window precisely: after processing right, the range is s[left..right] or nums[left..right], inclusive. Its state must exactly describe that range. For a fixed k-sum window, the invariant is that windowSum equals the sum of the current k elements. When right moves, add the incoming value; when the window exceeds k, subtract the outgoing value and move left.
For a variable window such as “longest substring with no repeated character,” the invariant is that the current range is valid: every character appears at most once. Expand right to consider a new candidate. If the state becomes invalid, advance left until validity is restored, updating the state for every removal. Only then evaluate a valid answer. This order prevents an invalid range from being recorded as the best one.
Minimum-window problems reverse the evaluation moment: once the window is valid, record its size before shrinking, then shrink while it remains valid. The shared principle is exact state: the counts, sum, or deque must always match the boundaries currently named by left and right.
JavaScript and TypeScript Templates
1. Fixed-size maximum-sum window
function maxFixedWindowSum(nums, k) {
if (k <= 0 || k > nums.length) return null;
let windowSum = 0;
for (let i = 0; i < k; i += 1) {
windowSum += nums[i];
}
let best = windowSum;
for (let right = k; right < nums.length; right += 1) {
windowSum += nums[right];
windowSum -= nums[right - k];
best = Math.max(best, windowSum);
}
return best;
}
The first loop builds the initial k-element range. In the second loop, adding nums[right] and subtracting nums[right - k] keeps the size and sum invariant intact. The code returns null for an invalid k; choose another documented contract only if the prompt specifies one.
2. Dynamic window for the longest unique substring
function lengthOfLongestSubstring(s) {
const lastSeen = new Map();
let left = 0;
let best = 0;
for (let right = 0; right < s.length; right += 1) {
const char = s[right];
if (lastSeen.has(char)) {
left = Math.max(left, lastSeen.get(char) + 1);
}
lastSeen.set(char, right);
best = Math.max(best, right - left + 1);
}
return best;
}
Here lastSeen stores the most recent global index of each character. The Math.max is critical: an older occurrence left of the current window must not move left backward. After the update, no repeated character remains inside the current window, so its length is safe to compare with best.
Fixed, Dynamic, Coverage, and Deque Variants
| Variant | Expand rule | Contract or cleanup rule |
|---|---|---|
| Fixed size | Add one incoming element. | Remove exactly one outgoing element once size exceeds k. |
| At most K | Add the right value and update counts. | While the constraint is violated, remove from left. |
| Minimum covering window | Expand until all requirements are covered. | Record first, then shrink while coverage remains valid. |
| Exact K | Often reduce to atMost(K) - atMost(K - 1). | Use the at-most repair logic in each helper. |
| Monotonic deque | Remove worse values from the deque tail, then append right. | Remove a deque head that fell left of the window. |
A deque is still a fixed-size sliding window, but it preserves only candidates that could become a future maximum or minimum. Store indices, not just values, so expired entries can be identified. Each index enters and leaves the deque at most once, which is why Sliding Window Maximum is O(n), not O(nk).
Worked Dry Run: Longest Substring Without Repeats
Use s = "pwwkew". At right = 0, the window is "p", so best is 1. At index 1, add w: "pw", best 2. At index 2, another w was last seen at index 1, so set left to max(0, 1 + 1) = 2; the valid window is now "w". Continue with k and e to get "wke" of length 3.
At index 5, w was last seen at index 2, so left becomes 3 and the window becomes "kew", also length 3. The answer is 3. The dry run shows why a duplicate moves left just past its most recent occurrence, rather than clearing all state or restarting at zero.
Complexity, Boundaries, and Edge Cases
| Variant | Time | Extra space |
|---|---|---|
| Fixed sum or frequency window | O(n) | O(1) or O(alphabet size) |
| Variable window with a map | O(n) | O(min(n, alphabet size)) |
| Monotonic deque window maximum | O(n) | O(k) |
| Minimum covering window | O(n + m) for source and pattern | O(alphabet size) |
Test an empty input, k = 1, k = nums.length, and invalid k. For count maps, delete a key when its count reaches zero if your distinct-count logic depends on map size. In a character problem, ask whether JavaScript UTF-16 code units are sufficient or whether the requirement is user-perceived Unicode characters. In a positive-number minimum-length sum problem, explicitly note that zero and negative numbers may invalidate the usual shrink proof.
Common Failure Modes
- Using a window for a non-contiguous subsequence or a pair-selection problem.
- Updating left without subtracting or decrementing the outgoing element from window state.
- Using
ifinstead ofwhilewhen several left moves may be needed to restore validity. - Recording a minimum-cover answer after shrinking, which can miss the valid candidate that existed first.
- Moving left backward in the last-seen-index template by omitting
Math.max. - Forgetting to evict deque indices that are outside the fixed window.
- Assuming the positive-number sum template works when negative values are allowed.
Deliberate Practice Ladder
- Implement Maximum Average Subarray I, then write the initial-window and slide steps without looking.
- Solve Longest Substring Without Repeating Characters using both a set-plus-while method and the last-seen-index method.
- Practice Permutation in String or Find All Anagrams to maintain equal-size frequency vectors.
- Solve Longest Repeating Character Replacement or Fruit Into Baskets to rehearse an at-most constraint.
- Finish with Minimum Window Substring and Sliding Window Maximum, explaining coverage and deque invariants out loud.
For every solution, manually trace a case that forces several contractions in a row. That is the fastest way to expose stale state and off-by-one errors.
Mock-Interview Explanation Checklist
- Confirm that the desired output is based on a contiguous range and identify fixed versus variable size.
- Name the exact state: sum, frequency map, number of distinct values, coverage count, or deque.
- State the invariant that connects the state to
[left, right]. - Explain when the answer is recorded: after a valid expansion, before shrinking a minimum window, or after a fixed-size slide.
- Justify why both boundaries move forward at most n times and give time and space complexity.
- Test empty input, a one-element window, repeated characters, no valid range, and the maximum-size range.
Connect This Pattern to the Rest of Your Prep
Sliding window is a same-direction boundary technique, while Two Pointers also includes opposite-end searches, merging, and read/write compaction. When a condition cannot be repaired by dropping a left prefix and instead requires remembering results for many smaller states, move to Dynamic Programming. Browse the LeetCode category and combine pattern drills with the software engineer interview questions guide.
GhOst may be used in personal preparation and mock interviews to rehearse a window invariant, explain a dry run, and review tests. In an actual interview or assessment, use assistance only where it is explicitly permitted. Check the applicable platform guidance and compatibility information before using any tool.
Frequently Asked Questions
Sliding Window fits a contiguous subarray or substring when its state can be updated as elements enter on the right and leave on the left. Fixed k, longest or shortest valid ranges, coverage, and at-most-K constraints are common signals.
A fixed window always contains k elements and removes one element for each new one. A dynamic window changes size: it expands right and contracts left only when a constraint must be repaired or a valid covering range can be minimized.
In standard templates, left and right only move forward. Each input element is added to state once and removed at most once; a monotonic deque also adds and removes each index at most once.
Avoid it for non-contiguous subsequences or arbitrary subsets. Also verify the shrink proof: the common minimum-length target-sum approach relies on positive values and can fail when negative numbers are allowed.
