Lesson 53 of 80
A window of two pointers moving together over a sequence, carrying its own running state — so you never recompute the overlap a naive approach redoes on every step.
16 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Plenty of "look at every contiguous chunk of the array/string" problems get solved naively by recomputing each chunk from scratch: for every starting position, walk forward and recompute a sum, a count, a set of characters. That redoes an enormous amount of overlapping work — most of two adjacent chunks is identical.
A sliding window keeps two pointers, start and end, marking the current chunk, and instead of recomputing when the window moves, it updates incrementally: add whatever the window just gained, remove whatever it just lost. The window slides instead of restarting.
Max sum of any subarray of size k (fixed-size window). Naive: for each starting index, sum the next k elements — O(n·k). Sliding window: compute the first window's sum once, then slide by subtracting the element that leaves and adding the one that enters.
function maxSumSubarray(arr, k) {
let windowSum = 0;
for (let i = 0; i < k; i++) windowSum += arr[i];
let maxSum = windowSum;
for (let end = k; end < arr.length; end++) {
windowSum += arr[end] - arr[end - k]; // gain one, lose one
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
maxSumSubarray([2, 1, 5, 1, 3, 2], 3); // 9 → [5, 1, 3]
That's O(n) total — each element is added to windowSum exactly once and subtracted exactly once, no matter how many windows there are.
Longest substring without repeating characters (variable-size window). Here the window's size isn't fixed — it grows while characters stay unique, and shrinks from the left the moment a repeat shows up.
function longestUniqueSubstring(str) {
const seen = new Map(); // char -> last index it appeared at
let start = 0;
let longest = 0;
for (let end = 0; end < str.length; end++) {
const char = str[end];
if (seen.has(char) && seen.get(char) >= start) {
start = seen.get(char) + 1; // jump start past the repeat
}
seen.set(char, end);
longest = Math.max(longest, end - start + 1);
}
return longest;
}
longestUniqueSubstring("abcabcbb"); // 3 → "abc"
end only ever moves forward, and start only ever moves forward — each index is visited a bounded number of times, giving O(n) instead of the O(n²) of checking every substring.
end inclusive or exclusive? arr[end - k] in the fixed-size example only works because end starts at k, one past the first window's last index — get that starting point wrong and the subtraction targets the wrong element.This builds directly on the two-pointer idea: instead of pointers moving toward each other from opposite ends, a sliding window's pointers move in the same direction, and the "state" living between them — a running sum, a map of characters seen — is what makes each slide O(1) instead of a re-scan. Same discipline of not redoing overlapping work, applied to a moving range instead of a converging pair.