The sliding window technique
Reuse the work you already did instead of recomputing every subarray.
Any question about a contiguous subarray or substring is a sliding window question. Instead of recomputing each window from scratch, you slide the boundaries and update the answer by the difference.
Fixed window
Largest sum of any k consecutive elements:
function maxWindowSum(items, k) {
let sum = 0;
for (let i = 0; i < k; i++) sum += items[i];
let best = sum;
for (let i = k; i < items.length; i++) {
sum += items[i] - items[i - k]; // add the newcomer, drop the leaver
best = Math.max(best, sum);
}
return best;
}
Each element is added once and removed once: O(n) instead of O(n × k).
Variable window
Grow the right edge greedily; shrink the left edge only while the window is invalid. Longest substring without repeating characters:
function longestUnique(text) {
const lastSeen = new Map();
let start = 0;
let best = 0;
for (let end = 0; end < text.length; end++) {
const ch = text[end];
// Jump the start past the previous copy — never backwards.
if (lastSeen.has(ch) && lastSeen.get(ch) >= start) {
start = lastSeen.get(ch) + 1;
}
lastSeen.set(ch, end);
best = Math.max(best, end - start + 1);
}
return best;
}
Both pointers only ever move forward, so despite the nested feel this is O(n) with O(k) space for the alphabet.
The template
- Extend
end, update the window state. - While the window breaks the constraint, advance
startand undo its contribution. - Record the answer when the window is valid.
Where it applies
"Longest substring with at most k distinct characters", "minimum window containing all of t", "maximum average subarray", "count subarrays with sum ≤ target". If the problem says contiguous and asks for a longest, shortest, or count, start here.
One caveat: with negative numbers, "shrink while invalid" can stop being monotonic. Sum-based windows assume non-negative values — otherwise reach for prefix sums and a hash map instead.